├── LICENSE ├── README.md ├── configs ├── derm_7pt.yaml ├── isic_2017.yaml ├── isic_2018.yaml └── isic_2019.yaml ├── lib ├── __init__.py ├── backbone │ ├── __init__.py │ ├── all_models.py │ ├── build_regnet.py │ ├── build_regnet_dropblock.py │ ├── efficientnet.py │ ├── regnet.py │ ├── regnet_dropblock.py │ └── regnet_yaml │ │ ├── RegNetX-1.6GF_dds_8gpu.yaml │ │ ├── RegNetX-12GF_dds_8gpu.yaml │ │ ├── RegNetX-16GF_dds_8gpu.yaml │ │ ├── RegNetX-200MF_dds_8gpu.yaml │ │ ├── RegNetX-3.2GF_dds_8gpu.yaml │ │ ├── RegNetX-32GF_dds_8gpu.yaml │ │ ├── RegNetX-4.0GF_dds_8gpu.yaml │ │ ├── RegNetX-400MF_dds_8gpu.yaml │ │ ├── RegNetX-6.4GF_dds_8gpu.yaml │ │ ├── RegNetX-600MF_dds_8gpu.yaml │ │ ├── RegNetX-8.0GF_dds_8gpu.yaml │ │ ├── RegNetX-800MF_dds_8gpu.yaml │ │ ├── RegNetY-1.6GF_dds_8gpu.yaml │ │ ├── RegNetY-12GF_dds_8gpu.yaml │ │ ├── RegNetY-16GF_dds_8gpu.yaml │ │ ├── RegNetY-200MF_dds_8gpu.yaml │ │ ├── RegNetY-3.2GF_dds_8gpu.yaml │ │ ├── RegNetY-32GF_dds_8gpu.yaml │ │ ├── RegNetY-4.0GF_dds_8gpu.yaml │ │ ├── RegNetY-400MF_dds_8gpu.yaml │ │ ├── RegNetY-6.4GF_dds_8gpu.yaml │ │ ├── RegNetY-600MF_dds_8gpu.yaml │ │ ├── RegNetY-8.0GF_dds_8gpu.yaml │ │ └── RegNetY-800MF_dds_8gpu.yaml ├── config │ ├── __init__.py │ └── default.py ├── core │ ├── __init__.py │ ├── combiner.py │ ├── evaluate.py │ └── function.py ├── data_transform │ ├── __init__.py │ ├── color_constancy.py │ ├── modified_randaugment.py │ └── transforms.py ├── dataset │ ├── __init__.py │ ├── baseset.py │ ├── derm_7pt.py │ └── isic.py ├── loss │ ├── __init__.py │ └── loss.py ├── modules │ ├── __init__.py │ ├── classifier_ops.py │ ├── dropblock.py │ ├── droplock_scheduler.py │ └── pooling_ops.py ├── net │ ├── __init__.py │ └── network.py └── utils │ ├── Nadam.py │ ├── __init__.py │ ├── lr_scheduler.py │ └── utils.py ├── main ├── _init_paths.py ├── jsons │ ├── converted_Derm_7pt_train.json │ └── readme.md ├── train.py └── valid.py ├── pretrained_models └── readme.md └── tools ├── convert_from_Derm_7pt.py ├── convert_from_ISIC_2017.py ├── convert_from_ISIC_2018.py ├── convert_from_ISIC_2019.py ├── dataset_files ├── Derm_7pt_test.json ├── Derm_7pt_train.json ├── Derm_7pt_valid.json ├── ISIC_2017_Test.csv ├── ISIC_2017_Train.csv ├── ISIC_2017_Val.csv ├── ISIC_2018_5foldcv_indices.pkl ├── ISIC_2018_Test.csv ├── ISIC_2018_Train.csv ├── ISIC_2018_Val.csv ├── ISIC_2019_Test.csv └── ISIC_2019_Train.csv └── resize_image_ISIC_2019.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 yaopengUSTC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Single Model Deep Learning on Imbalanced Small Datasets for Skin Lesion Classification 2 | Peng Yao, Shuwei Shen, Mengjuan Xu, Peng Liu, Fan Zhang, Jinyu Xing, Pengfei Shao, Benjamin Kaffenberger, and Ronald X. Xu* 3 | 4 | This repository is the official PyTorch implementation of paper [Single Model Deep Learning on Imbalanced Small Datasets for Skin Lesion Classification](https://arxiv.org/abs/2102.01284). 5 | 6 | ## Main requirements 7 | 8 | * **torch == 1.5.1** 9 | * **Python 3** 10 | 11 | ## Environmental settings 12 | This repository is developed using python **3.6** on Ubuntu **16.04 LTS**. The CUDA version is **9.2**. For all experiments, we use **two NVIDIA 2080ti GPU card** for training and testing. 13 | 14 | ## Usage 15 | ```bash 16 | # To train ISIC 2018: 17 | python main/train.py --cfg configs/isic_2018.yaml 18 | 19 | # To validate with the best model: 20 | python main/valid.py --cfg configs/isic_2018.yaml 21 | ``` 22 | 23 | You can change the experimental setting by simply modifying the parameter in the yaml file. 24 | 25 | ## Data format 26 | 27 | The annotation of a dataset is a dict consisting of two field: `annotations` and `num_classes`. 28 | The field `annotations` is a list of dict with 29 | `image_id`, `category_id`, `derm_height`, `derm_width` and `derm_path`. 30 | 31 | Here is an example. 32 | ``` 33 | { 34 | 'annotations': [ 35 | { 36 | 'image_id': ISIC_0031633, 37 | 'category_id':4, 38 | 'derm_height':450, 39 | 'derm_width':600, 40 | 'derm_path': '/work/image/skin_cancer/HAM10000/ISIC_0031633.jpg' 41 | }, 42 | ... 43 | ] 44 | 'num_classes':7 45 | } 46 | ``` 47 | You can use the following code to convert from the original format of Derm7PT, ISIC 2017, ISIC 2018 or ISIC 2019. 48 | The images and annotations of ISIC can be downloaded at [ISIC](https://challenge.isic-archive.com/data/). 49 | The images and annotations of Derm7PT can be downloaded at [Derm7PT](https://derm.cs.sfu.ca). 50 | 51 | ```bash 52 | # Convert from the original format of ISIC 2017 53 | python tools/convert_from_ISIC_2017.py --file ISIC_2017.csv --root /work/image/skin_cancer/ISIC_2017 --sp /work/skin_cancer/jsons 54 | ``` 55 | 56 | ## Contacts 57 | If you have any questions about our work, please do not hesitate to contact us by email. 58 | 59 | Peng Yao: yaopeng@ustc.edu.cn 60 | 61 | -------------------------------------------------------------------------------- /configs/derm_7pt.yaml: -------------------------------------------------------------------------------- 1 | NAME: '_1' 2 | OUTPUT_DIR: './output/derm_7pt' 3 | SHOW_STEP: 500 4 | SAVE_STEP: 2 5 | VALID_STEP: 2 6 | INPUT_SIZE: (224, 224) 7 | COLOR_SPACE: 'RGB' 8 | CPU_MODE: False 9 | GPUS: [0, 1] 10 | 11 | DATASET: 12 | DATASET: 'derm_7pt' 13 | DATA_TYPE: 'jpg' 14 | TRAIN_JSON: './jsons/converted_Derm_7pt_train.json' 15 | VALID_JSON: './jsons/converted_Derm_7pt_val.json' 16 | TEST_JSON: './jsons/converted_Derm_7pt_test.json' 17 | CLASS_NAME: ['BCC', 'NV', 'MEL', 'MISC', 'SK'] 18 | 19 | BACKBONE: 20 | TYPE: 'RegNetY_800MF_DropBlock' 21 | BBN: False 22 | PRETRAINED: True 23 | FREEZE: False 24 | PRE_FREEZE: False 25 | PRE_FREEZE_EPOCH: 5 26 | DROP: 27 | BLOCK_PROB: 0.1 28 | BLOCK_SIZE: 5 29 | NR_STEPS: 50000 30 | OUT_PROB: 0.1 31 | 32 | MODULE: 33 | TYPE: 'GAP' 34 | 35 | LOSS: 36 | WEIGHT_POWER: 1.0 37 | EXTRA_WEIGHT: [1.0, 1.0, 1.0, 1.0, 1.0] 38 | LOSS_TYPE: 'MWNLoss' 39 | SCHEDULER: 're_weight' 40 | DRW_EPOCH: 50 41 | CLS_EPOCH_MIN: 20 42 | CLS_EPOCH_MAX: 60 43 | FOCAL: 44 | TYPE: 'sigmoid' 45 | SIGMOID: 'normal' 46 | GHMC: 47 | BINS: 10 48 | MOMENTUM: 0.0 49 | MWNL: 50 | BETA: 0.1 51 | TYPE: "fix" 52 | SIGMOID: 'normal' 53 | 54 | CLASSIFIER: 55 | TYPE: 'FC' 56 | BIAS: True 57 | 58 | TRAIN: 59 | BATCH_SIZE: 64 60 | MAX_EPOCH: 70 61 | NUM_WORKERS: 16 62 | TENSORBOARD: 63 | ENABLE: False 64 | SAMPLER: 65 | TYPE: 'default' 66 | IMAGE_TYPE: 'derm' 67 | BORDER_CROP: 'pixel' 68 | BORDER_CROP_PIXEL: 25 69 | IMAGE_RESIZE: True 70 | IMAGE_RESIZE_SHORT: 336 71 | AUGMENT: 72 | NEED_AUGMENT: True 73 | AUG_METHOD: 'v1_1' 74 | AUG_PROB: 0.7 75 | AUG_MAG: 10 76 | AUG_LAYER_NUM: 2 77 | DUAL_SAMPLER: 78 | TYPE: 'reverse' 79 | MULTI_CROP: 80 | ENABLE: True 81 | CROP_NUM: 16 82 | L_REGION: 1.0 83 | S_REGION: 1.0 84 | SCHEME: 'average' 85 | OPTIMIZER: 86 | TYPE: 'ADAM' 87 | BASE_LR: 0.0002 88 | MOMENTUM: 0.9 89 | WEIGHT_DECAY: 1e-4 90 | LR_SCHEDULER: 91 | TYPE: 'multistep' 92 | LR_STEP: [30, 40, 50, 60] 93 | LR_FACTOR: 0.1 94 | 95 | TEST: 96 | BATCH_SIZE: 240 97 | NUM_WORKERS: 16 98 | 99 | -------------------------------------------------------------------------------- /configs/isic_2017.yaml: -------------------------------------------------------------------------------- 1 | NAME: '_1' 2 | OUTPUT_DIR: './output/isic_2017' 3 | SHOW_STEP: 500 4 | SAVE_STEP: 2 5 | VALID_STEP: 2 6 | INPUT_SIZE: (224, 224) 7 | COLOR_SPACE: 'RGB' 8 | CPU_MODE: False 9 | GPUS: [0, 1] 10 | 11 | DATASET: 12 | DATASET: 'isic_2017' 13 | DATA_TYPE: 'jpg' 14 | TRAIN_JSON: './jsons/converted_ISIC_2017_Train_Small.json' 15 | VALID_JSON: './jsons/converted_ISIC_2017_Val_Small.json' 16 | TEST_JSON: './jsons/converted_ISIC_2017_Test_Small.json' 17 | CLASS_NAME: ['MEL', 'SK', 'NV'] 18 | 19 | BACKBONE: 20 | TYPE: 'RegNetY_1.6GF_DropBlock' 21 | BBN: False 22 | PRETRAINED: True 23 | FREEZE: False 24 | PRE_FREEZE: False 25 | PRE_FREEZE_EPOCH: 5 26 | DROP: 27 | BLOCK_PROB: 0.1 28 | BLOCK_SIZE: 5 29 | NR_STEPS: 50000 30 | OUT_PROB: 0.1 31 | 32 | MODULE: 33 | TYPE: 'GAP' 34 | 35 | LOSS: 36 | WEIGHT_POWER: 1.1 37 | EXTRA_WEIGHT: [1.0, 1.0, 1.0] 38 | LOSS_TYPE: 'MWNLoss' 39 | SCHEDULER: 're_weight' 40 | DRW_EPOCH: 50 41 | CLS_EPOCH_MIN: 20 42 | CLS_EPOCH_MAX: 60 43 | FOCAL: 44 | TYPE: 'sigmoid' 45 | SIGMOID: 'normal' 46 | GHMC: 47 | BINS: 10 48 | MOMENTUM: 0.0 49 | MWNL: 50 | BETA: 0.1 51 | TYPE: "fix" 52 | SIGMOID: 'normal' 53 | 54 | CLASSIFIER: 55 | TYPE: 'FC' 56 | BIAS: True 57 | 58 | TRAIN: 59 | BATCH_SIZE: 64 60 | MAX_EPOCH: 70 61 | NUM_WORKERS: 16 62 | TENSORBOARD: 63 | ENABLE: False 64 | SAMPLER: 65 | TYPE: 'default' 66 | BORDER_CROP: 'ratio' 67 | BORDER_CROP_PIXEL: 0 68 | BORDER_CROP_RATIO: 0.0 69 | IMAGE_RESIZE: True 70 | IMAGE_RESIZE_SHORT: 336 71 | AUGMENT: 72 | NEED_AUGMENT: True 73 | AUG_METHOD: 'v1_1' 74 | AUG_PROB: 0.7 75 | AUG_MAG: 10 76 | AUG_LAYER_NUM: 2 77 | DUAL_SAMPLER: 78 | TYPE: 'reverse' 79 | MULTI_CROP: 80 | ENABLE: True 81 | CROP_NUM: 16 82 | L_REGION: 1.0 83 | S_REGION: 1.0 84 | SCHEME: 'average' 85 | OPTIMIZER: 86 | TYPE: 'ADAM' 87 | BASE_LR: 0.0001 88 | MOMENTUM: 0.9 89 | WEIGHT_DECAY: 1e-4 90 | LR_SCHEDULER: 91 | TYPE: 'multistep' 92 | LR_STEP: [30, 40, 50, 60] 93 | LR_FACTOR: 0.1 94 | 95 | TEST: 96 | BATCH_SIZE: 240 97 | NUM_WORKERS: 16 98 | 99 | -------------------------------------------------------------------------------- /configs/isic_2018.yaml: -------------------------------------------------------------------------------- 1 | NAME: '_1' 2 | OUTPUT_DIR: './output/isic_2018' 3 | SHOW_STEP: 500 4 | SAVE_STEP: 2 5 | VALID_STEP: 2 6 | INPUT_SIZE: (224, 224) 7 | COLOR_SPACE: 'RGB' 8 | CPU_MODE: False 9 | GPUS: [0, 1] 10 | 11 | DATASET: 12 | DATASET: 'isic_2018' 13 | DATA_TYPE: 'jpg' 14 | TRAIN_JSON: './jsons/converted_ISIC_2018_Train.json' 15 | VALID_JSON: './jsons/converted_ISIC_2018_Val.json' 16 | TEST_JSON: './jsons/converted_ISIC_2018_Test.json' 17 | CLASS_NAME: ['MEL', 'NV', 'BCC', 'AKIEC', 'BKL', 'DF', 'VASC'] 18 | 19 | BACKBONE: 20 | TYPE: 'RegNetY_3.2GF_DropBlock' 21 | BBN: False 22 | PRETRAINED: True 23 | FREEZE: False 24 | PRE_FREEZE: False 25 | PRE_FREEZE_EPOCH: 5 26 | DROP: 27 | BLOCK_PROB: 0.1 28 | BLOCK_SIZE: 5 29 | NR_STEPS: 50000 30 | OUT_PROB: 0.1 31 | 32 | MODULE: 33 | TYPE: 'GAP' 34 | 35 | LOSS: 36 | WEIGHT_POWER: 1.2 37 | EXTRA_WEIGHT: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] 38 | LOSS_TYPE: 'MWNLoss' 39 | SCHEDULER: 'cls' 40 | DRW_EPOCH: 50 41 | CLS_EPOCH_MIN: 20 42 | CLS_EPOCH_MAX: 60 43 | FOCAL: 44 | TYPE: 'sigmoid' 45 | SIGMOID: 'enlarge' 46 | GHMC: 47 | BINS: 10 48 | MOMENTUM: 0.0 49 | MWNL: 50 | BETA: 0.1 51 | TYPE: "fix" 52 | SIGMOID: 'enlarge' 53 | 54 | CLASSIFIER: 55 | TYPE: 'FC' 56 | BIAS: True 57 | 58 | TRAIN: 59 | BATCH_SIZE: 64 60 | MAX_EPOCH: 70 61 | NUM_WORKERS: 16 62 | TENSORBOARD: 63 | ENABLE: False 64 | SAMPLER: 65 | TYPE: 'default' 66 | BORDER_CROP: 'ratio' 67 | BORDER_CROP_PIXEL: 0 68 | BORDER_CROP_RATIO: 0.0 69 | IMAGE_RESIZE: True 70 | IMAGE_RESIZE_SHORT: 450 71 | AUGMENT: 72 | NEED_AUGMENT: True 73 | AUG_METHOD: 'v1_1' 74 | AUG_PROB: 0.7 75 | AUG_MAG: 10 76 | AUG_LAYER_NUM: 2 77 | DUAL_SAMPLER: 78 | TYPE: 'reverse' 79 | MULTI_CROP: 80 | ENABLE: True 81 | CROP_NUM: 16 82 | L_REGION: 1.0 83 | S_REGION: 1.0 84 | SCHEME: 'average' 85 | MULTI_SCALE: 86 | ENABLE: False 87 | SCALE_NUM: 12 88 | OPTIMIZER: 89 | TYPE: 'ADAM' 90 | BASE_LR: 0.0005 91 | MOMENTUM: 0.9 92 | WEIGHT_DECAY: 1e-4 93 | LR_SCHEDULER: 94 | TYPE: 'multistep' 95 | LR_STEP: [30, 40, 50, 60] 96 | LR_FACTOR: 0.1 97 | 98 | TEST: 99 | BATCH_SIZE: 240 100 | NUM_WORKERS: 16 101 | 102 | -------------------------------------------------------------------------------- /configs/isic_2019.yaml: -------------------------------------------------------------------------------- 1 | NAME: '_1' 2 | OUTPUT_DIR: './output/isic_2019' 3 | SHOW_STEP: 500 4 | SAVE_STEP: 2 5 | VALID_STEP: 2 6 | INPUT_SIZE: (224, 224) 7 | COLOR_SPACE: 'RGB' 8 | CPU_MODE: False 9 | GPUS: [0, 1] 10 | 11 | DATASET: 12 | DATASET: 'isic_2019' 13 | DATA_TYPE: 'jpg' 14 | TRAIN_JSON: './jsons/converted_ISIC_2019_Train.json' 15 | VALID_JSON: './jsons/converted_ISIC_2019_val_new_2.json' 16 | TEST_JSON: './jsons/converted_ISIC_2019_Test.json' 17 | VALID_ADD_ONE_CLASS: False 18 | CLASS_NAME: ['MEL', 'NV', 'BCC', 'AK', 'BKL', 'DF', 'VASC', 'SCC'] 19 | 20 | BACKBONE: 21 | TYPE: 'RegNetY_8.0GF_DropBlock' 22 | BBN: False 23 | PRETRAINED: True 24 | FREEZE: False 25 | PRE_FREEZE: False 26 | PRE_FREEZE_EPOCH: 5 27 | DROP: 28 | BLOCK_PROB: 0.1 29 | BLOCK_SIZE: 5 30 | NR_STEPS: 50000 31 | OUT_PROB: 0.1 32 | 33 | MODULE: 34 | TYPE: 'GAP' 35 | 36 | LOSS: 37 | WEIGHT_POWER: 1.2 38 | EXTRA_WEIGHT: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] 39 | LOSS_TYPE: 'MWNLoss' 40 | SCHEDULER: 'cls' 41 | DRW_EPOCH: 50 42 | CLS_EPOCH_MIN: 20 43 | CLS_EPOCH_MAX: 60 44 | FOCAL: 45 | TYPE: 'sigmoid' 46 | SIGMOID: 'enlarge' 47 | GHMC: 48 | BINS: 10 49 | MOMENTUM: 0.0 50 | MWNL: 51 | BETA: 0.1 52 | TYPE: "fix" 53 | SIGMOID: 'enlarge' 54 | 55 | CLASSIFIER: 56 | TYPE: 'FC' 57 | BIAS: True 58 | 59 | TRAIN: 60 | BATCH_SIZE: 32 61 | MAX_EPOCH: 70 62 | NUM_WORKERS: 16 63 | TENSORBOARD: 64 | ENABLE: False 65 | SAMPLER: 66 | TYPE: 'default' 67 | BORDER_CROP: 'ratio' 68 | BORDER_CROP_PIXEL: 0 69 | BORDER_CROP_RATIO: 0.0 70 | IMAGE_RESIZE: True 71 | IMAGE_RESIZE_SHORT: 450 72 | AUGMENT: 73 | NEED_AUGMENT: True 74 | AUG_METHOD: 'v1_1' 75 | AUG_PROB: 0.7 76 | AUG_MAG: 10 77 | AUG_LAYER_NUM: 2 78 | DUAL_SAMPLER: 79 | TYPE: 'reverse' 80 | MULTI_CROP: 81 | ENABLE: True 82 | CROP_NUM: 16 83 | L_REGION: 1.0 84 | S_REGION: 1.0 85 | SCHEME: 'average' 86 | MULTI_SCALE: 87 | ENABLE: False 88 | SCALE_NUM: 12 89 | OPTIMIZER: 90 | TYPE: 'ADAM' 91 | BASE_LR: 0.0002 92 | MOMENTUM: 0.9 93 | WEIGHT_DECAY: 1e-4 94 | LR_SCHEDULER: 95 | TYPE: 'multistep' 96 | LR_STEP: [30, 40, 50, 60] 97 | LR_FACTOR: 0.1 98 | 99 | TEST: 100 | BATCH_SIZE: 240 101 | NUM_WORKERS: 16 102 | 103 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /lib/backbone/__init__.py: -------------------------------------------------------------------------------- 1 | from .all_models import * 2 | from .build_regnet import * 3 | from .regnet import * 4 | from .regnet_dropblock import * 5 | from .efficientnet import * 6 | -------------------------------------------------------------------------------- /lib/backbone/all_models.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | from lib.modules import FCNorm 3 | import copy 4 | from torchvision import models 5 | import pretrainedmodels 6 | from .efficientnet import efficientnet_b0 7 | from .efficientnet import efficientnet_b1 8 | from .efficientnet import efficientnet_b2 9 | from .efficientnet import efficientnet_b3 10 | from .efficientnet import efficientnet_b4 11 | from .efficientnet import efficientnet_b5 12 | from .efficientnet import efficientnet_b6 13 | from .efficientnet import efficientnet_b7 14 | from .build_regnet import RegNetY_200MF 15 | from .build_regnet import RegNetX_200MF 16 | from .build_regnet import RegNetY_400MF 17 | from .build_regnet import RegNetX_400MF 18 | from .build_regnet import RegNetY_600MF 19 | from .build_regnet import RegNetX_600MF 20 | from .build_regnet import RegNetY_800MF 21 | from .build_regnet import RegNetX_800MF 22 | from .build_regnet import RegNetY_1_6_GF 23 | from .build_regnet import RegNetX_1_6_GF 24 | from .build_regnet import RegNetX_3_2_GF 25 | from .build_regnet import RegNetY_3_2_GF 26 | from .build_regnet import RegNetY_4_0_GF 27 | from .build_regnet import RegNetX_4_0_GF 28 | from .build_regnet import RegNetX_6_4_GF 29 | from .build_regnet import RegNetY_6_4_GF 30 | from .build_regnet import RegNetY_8_0_GF 31 | from .build_regnet import RegNetX_8_0_GF 32 | from .build_regnet import RegNetX_1_2_0_GF 33 | from .build_regnet import RegNetY_1_2_0_GF 34 | from .build_regnet import RegNetY_1_6_0_GF 35 | from .build_regnet import RegNetX_1_6_0_GF 36 | from .build_regnet import RegNetY_3_2_0_GF 37 | from .build_regnet import RegNetX_3_2_0_GF 38 | from .build_regnet_dropblock import RegNetY_8_0_0_MF_DropBlock 39 | from .build_regnet_dropblock import RegNetY_1_6_GF_DropBlock 40 | from .build_regnet_dropblock import RegNetY_3_2_GF_DropBlock 41 | from .build_regnet_dropblock import RegNetY_8_0_GF_DropBlock 42 | from .build_regnet_dropblock import RegNetY_1_6_0_GF_DropBlock 43 | 44 | 45 | def get_model(model_name, pretrained=False): 46 | """Returns a CNN model 47 | Args: 48 | model_name: model name 49 | pretrained: True or False 50 | Returns: 51 | model: the desired model 52 | Raises: 53 | ValueError: If model name is not recognized. 54 | """ 55 | if pretrained == False: 56 | pt = None 57 | else: 58 | pt = 'imagenet' 59 | 60 | if model_name == 'Vgg11': 61 | return models.vgg11(pretrained=pretrained) 62 | elif model_name == 'Vgg13': 63 | return models.vgg13(pretrained=pretrained) 64 | elif model_name == 'Vgg16': 65 | return models.vgg16(pretrained=pretrained) 66 | elif model_name == 'Vgg19': 67 | return models.vgg19(pretrained=pretrained) 68 | elif model_name == 'Resnet18': 69 | return models.resnet18(pretrained=pretrained) 70 | elif model_name == 'Resnet34': 71 | return models.resnet34(pretrained=pretrained) 72 | elif model_name == 'Resnet50': 73 | return models.resnet50(pretrained=pretrained) 74 | elif model_name == 'Resnet101': 75 | return models.resnet101(pretrained=pretrained) 76 | elif model_name == 'Resnet152': 77 | return models.resnet152(pretrained=pretrained) 78 | elif model_name == 'Dense121': 79 | return models.densenet121(pretrained=pretrained) 80 | elif model_name == 'Dense169': 81 | return models.densenet169(pretrained=pretrained) 82 | elif model_name == 'Dense201': 83 | return models.densenet201(pretrained=pretrained) 84 | elif model_name == 'Dense161': 85 | return models.densenet161(pretrained=pretrained) 86 | elif model_name == 'SENet50': 87 | return pretrainedmodels.__dict__['se_resnet50'](num_classes=1000, pretrained=pt) 88 | elif model_name == 'SENet101': 89 | return pretrainedmodels.__dict__['se_resnet101'](num_classes=1000, pretrained=pt) 90 | elif model_name == 'SENet152': 91 | return pretrainedmodels.__dict__['se_resnet152'](num_classes=1000, pretrained=pt) 92 | elif model_name == 'SENet154': 93 | return pretrainedmodels.__dict__['senet154'](num_classes=1000, pretrained=pt) 94 | elif model_name == 'Efficient_b0': 95 | return efficientnet_b0(num_classes=1000, pretrained=pt) 96 | elif model_name == 'Efficient_b1': 97 | return efficientnet_b1(num_classes=1000, pretrained=pt) 98 | elif model_name == 'Efficient_b2': 99 | return efficientnet_b2(num_classes=1000, pretrained=pt) 100 | elif model_name == 'Efficient_b3': 101 | return efficientnet_b3(num_classes=1000, pretrained=pt) 102 | elif model_name == 'Efficient_b4': 103 | return efficientnet_b4(num_classes=1000, pretrained=pt) 104 | elif model_name == 'Efficient_b5': 105 | return efficientnet_b5(num_classes=1000, pretrained=pt) 106 | elif model_name == 'Efficient_b6': 107 | return efficientnet_b6(num_classes=1000, pretrained=pt) 108 | elif model_name == 'Efficient_b7': 109 | return efficientnet_b7(num_classes=1000, pretrained=pt) 110 | elif model_name == 'RegNetX_200MF': 111 | return RegNetX_200MF(num_classes=1000, pretrained=pt) 112 | elif model_name == 'RegNetX_400MF': 113 | return RegNetX_400MF(num_classes=1000, pretrained=pt) 114 | elif model_name == 'RegNetX_600MF': 115 | return RegNetX_600MF(num_classes=1000, pretrained=pt) 116 | elif model_name == 'RegNetX_800MF': 117 | return RegNetX_800MF(num_classes=1000, pretrained=pt) 118 | elif model_name == 'RegNetX_1.6GF': 119 | return RegNetX_1_6_GF(num_classes=1000, pretrained=pt) 120 | elif model_name == 'RegNetX_3.2GF': 121 | return RegNetX_3_2_GF(num_classes=1000, pretrained=pt) 122 | elif model_name == 'RegNetX_4.0GF': 123 | return RegNetX_4_0_GF(num_classes=1000, pretrained=pt) 124 | elif model_name == 'RegNetX_6.4GF': 125 | return RegNetX_6_4_GF(num_classes=1000, pretrained=pt) 126 | elif model_name == 'RegNetX_8.0GF': 127 | return RegNetX_8_0_GF(num_classes=1000, pretrained=pt) 128 | elif model_name == 'RegNetX_12GF': 129 | return RegNetX_1_2_0_GF(num_classes=1000, pretrained=pt) 130 | elif model_name == 'RegNetX_16GF': 131 | return RegNetX_1_6_0_GF(num_classes=1000, pretrained=pt) 132 | elif model_name == 'RegNetX_32GF': 133 | return RegNetX_3_2_0_GF(num_classes=1000, pretrained=pt) 134 | elif model_name == 'RegNetY_200MF': 135 | return RegNetY_200MF(num_classes=1000, pretrained=pt) 136 | elif model_name == 'RegNetY_400MF': 137 | return RegNetY_400MF(num_classes=1000, pretrained=pt) 138 | elif model_name == 'RegNetY_600MF': 139 | return RegNetY_600MF(num_classes=1000, pretrained=pt) 140 | elif model_name == 'RegNetY_800MF': 141 | return RegNetY_800MF(num_classes=1000, pretrained=pt) 142 | elif model_name == 'RegNetY_1.6GF': 143 | return RegNetY_1_6_GF(num_classes=1000, pretrained=pt) 144 | elif model_name == 'RegNetY_3.2GF': 145 | return RegNetY_3_2_GF(num_classes=1000, pretrained=pt) 146 | elif model_name == 'RegNetY_4.0GF': 147 | return RegNetY_4_0_GF(num_classes=1000, pretrained=pt) 148 | elif model_name == 'RegNetY_6.4GF': 149 | return RegNetY_6_4_GF(num_classes=1000, pretrained=pt) 150 | elif model_name == 'RegNetY_8.0GF': 151 | return RegNetY_8_0_GF(num_classes=1000, pretrained=pt) 152 | elif model_name == 'RegNetY_12GF': 153 | return RegNetY_1_2_0_GF(num_classes=1000, pretrained=pt) 154 | elif model_name == 'RegNetY_16GF': 155 | return RegNetY_1_6_0_GF(num_classes=1000, pretrained=pt) 156 | elif model_name == 'RegNetY_32GF': 157 | return RegNetY_3_2_0_GF(num_classes=1000, pretrained=pt) 158 | elif model_name == 'RegNetY_800MF_DropBlock': 159 | return RegNetY_8_0_0_MF_DropBlock(num_classes=1000, pretrained=pt) 160 | elif model_name == 'RegNetY_1.6GF_DropBlock': 161 | return RegNetY_1_6_GF_DropBlock(num_classes=1000, pretrained=pt) 162 | elif model_name == 'RegNetY_3.2GF_DropBlock': 163 | return RegNetY_3_2_GF_DropBlock(num_classes=1000, pretrained=pt) 164 | elif model_name == 'RegNetY_8.0GF_DropBlock': 165 | return RegNetY_8_0_GF_DropBlock(num_classes=1000, pretrained=pt) 166 | elif model_name == 'RegNetY_16GF_DropBlock': 167 | return RegNetY_1_6_0_GF_DropBlock(num_classes=1000, pretrained=pt) 168 | else: 169 | raise ValueError('Name of model unknown %s' % model_name) 170 | 171 | 172 | def modify_last_layer(model_name, model, num_classes, cfg): 173 | """modify the last layer of the CNN model to fit the num_classes 174 | Args: 175 | model_name: model name 176 | model: CNN model 177 | num_classes: class number 178 | Returns: 179 | model: the desired model 180 | """ 181 | if 'Vgg' in model_name: 182 | num_ftrs = model.classifier._modules['6'].in_features 183 | model.classifier._modules['6'] = classifier(num_ftrs, num_classes, cfg) 184 | last_layer = model.classifier._modules['6'] 185 | elif 'Dense' in model_name: 186 | num_ftrs = model.classifier.in_features 187 | model.classifier = classifier(num_ftrs, num_classes, cfg) 188 | last_layer = model.classifier 189 | elif 'Resnet' in model_name: 190 | num_ftrs = model.fc.in_features 191 | model.fc = classifier(num_ftrs, num_classes, cfg) 192 | last_layer = model.fc 193 | elif 'Efficient' in model_name: 194 | num_ftrs = model._fc.in_features 195 | model._fc = classifier(num_ftrs, num_classes, cfg) 196 | last_layer = model._fc 197 | elif 'RegNet' in model_name: 198 | num_ftrs = model.head.fc.in_features 199 | model.head.fc = classifier(num_ftrs, num_classes, cfg) 200 | last_layer = model.head.fc 201 | else: 202 | num_ftrs = model.last_linear.in_features 203 | model.last_linear = classifier(num_ftrs, num_classes, cfg) 204 | last_layer = model.last_linear 205 | # print(model) 206 | return model, last_layer 207 | 208 | 209 | def classifier(num_features, num_classes, cfg): 210 | bias_flag = cfg.CLASSIFIER.BIAS 211 | 212 | if cfg.CLASSIFIER.TYPE == "FCNorm": 213 | last_linear = FCNorm(num_features, num_classes) 214 | elif cfg.CLASSIFIER.TYPE == "FC": 215 | last_linear = nn.Linear(num_features, num_classes, bias=bias_flag) 216 | else: 217 | raise NotImplementedError 218 | return last_linear 219 | 220 | 221 | def get_bbn_model(model_name, model): 222 | """modify the normal CNN model to BBN model. Only supports Resnet and RegNet model. 223 | Args: 224 | model_name: model name 225 | model: CNN model 226 | Returns: 227 | model: the desired model 228 | """ 229 | if 'Resnet' in model_name: 230 | model.bbn_backbone = nn.Sequential( 231 | model.conv1, 232 | model.bn1, 233 | model.relu, 234 | model.maxpool, 235 | model.layer1, 236 | model.layer2, 237 | model.layer3 238 | ) 239 | model.bbn_cb_block = model.layer4 240 | model.bbn_rb_block = copy.deepcopy(model.bbn_cb_block) 241 | elif 'RegNet' in model_name: 242 | if 'DropBlock' in model_name: 243 | model.bbn_backbone = nn.Sequential( 244 | model.stem, 245 | model.s1, 246 | model.s2, 247 | model.s3, 248 | model.s3_drop_block 249 | ) 250 | model.bbn_cb_block = nn.Sequential( 251 | model.s4, 252 | model.s4_drop_block 253 | ) 254 | model.bbn_drop_out = model.head.dropout 255 | else: 256 | model.bbn_backbone = nn.Sequential( 257 | model.stem, 258 | model.s1, 259 | model.s2, 260 | model.s3 261 | ) 262 | model.bbn_cb_block = model.s4 263 | 264 | model.bbn_rb_block = copy.deepcopy(model.bbn_cb_block) 265 | else: 266 | raise ValueError('Model %s does not support bbn structure.' % model_name) 267 | 268 | return model 269 | 270 | 271 | def get_feature_length(model_name, model): 272 | """get the feature length of the last feature layer 273 | Args: 274 | model_name: model name 275 | model: CNN model 276 | Returns: 277 | num_ftrs: the feature length of the last feature layer 278 | """ 279 | if 'Vgg' in model_name: 280 | num_ftrs = model.classifier._modules['6'].in_features 281 | elif 'Dense' in model_name: 282 | num_ftrs = model.classifier.in_features 283 | elif 'Resnet' in model_name: 284 | num_ftrs = model.fc.in_features 285 | elif 'Efficient' in model_name: 286 | num_ftrs = model._fc.in_features 287 | elif 'RegNet' in model_name: 288 | num_ftrs = model.head.fc.in_features 289 | else: 290 | num_ftrs = model.last_linear.in_features 291 | 292 | return num_ftrs 293 | 294 | -------------------------------------------------------------------------------- /lib/backbone/build_regnet_dropblock.py: -------------------------------------------------------------------------------- 1 | from .regnet_dropblock import RegNet_DropBlock 2 | import torch 3 | import os 4 | import yaml 5 | 6 | 7 | pretrained_settings = { 8 | 'regnet': { 9 | 'imagenet': { 10 | 'input_space': 'RGB', 11 | 'input_size': [3, 224, 224], 12 | 'input_range': [0, 1], 13 | 'mean': [0.485, 0.456, 0.406], 14 | 'std': [0.229, 0.224, 0.225], 15 | 'num_classes': 1000 16 | } 17 | }, 18 | } 19 | 20 | 21 | def initialize_pretrained_model(model, num_classes, settings): 22 | assert num_classes == settings['num_classes'], 'num_classes should be {}, but is {}'.format( 23 | settings['num_classes'], num_classes) 24 | model.input_space = settings['input_space'] 25 | model.input_size = settings['input_size'] 26 | model.input_range = settings['input_range'] 27 | model.mean = settings['mean'] 28 | model.std = settings['std'] 29 | 30 | 31 | def RegNetY_8_0_0_MF_DropBlock(num_classes=1000, pretrained='imagenet'): 32 | f = open('../lib/backbone/regnet_yaml/RegNetY-800MF_dds_8gpu.yaml') 33 | config = yaml.load(f, Loader=yaml.FullLoader) 34 | model = RegNet_DropBlock(config) 35 | # print(model) 36 | last_checkpoint = '../pretrained_models/RegNetY-800MF_dds_8gpu.pyth' 37 | err_str = "Checkpoint '{}' not found" 38 | assert os.path.exists(last_checkpoint), err_str.format(last_checkpoint) 39 | checkpoint = torch.load(last_checkpoint, map_location="cpu") 40 | model.load_state_dict(checkpoint["model_state"]) 41 | print('have loaded checkpoint from {}'.format(last_checkpoint)) 42 | if pretrained is not None: 43 | settings = pretrained_settings['regnet'][pretrained] 44 | initialize_pretrained_model(model, num_classes, settings) 45 | return model 46 | 47 | 48 | def RegNetY_1_6_GF_DropBlock(num_classes=1000, pretrained='imagenet'): 49 | f = open('../lib/backbone/regnet_yaml/RegNetY-1.6GF_dds_8gpu.yaml') 50 | config = yaml.load(f, Loader=yaml.FullLoader) 51 | model = RegNet_DropBlock(config) 52 | # print(model) 53 | last_checkpoint = '../pretrained_models/RegNetY-1.6GF_dds_8gpu.pyth' 54 | err_str = "Checkpoint '{}' not found" 55 | assert os.path.exists(last_checkpoint), err_str.format(last_checkpoint) 56 | checkpoint = torch.load(last_checkpoint, map_location="cpu") 57 | model.load_state_dict(checkpoint["model_state"]) 58 | print('have loaded checkpoint from {}'.format(last_checkpoint)) 59 | if pretrained is not None: 60 | settings = pretrained_settings['regnet'][pretrained] 61 | initialize_pretrained_model(model, num_classes, settings) 62 | return model 63 | 64 | 65 | def RegNetY_3_2_GF_DropBlock(num_classes=1000, pretrained='imagenet'): 66 | f = open('../lib/backbone/regnet_yaml/RegNetY-3.2GF_dds_8gpu.yaml') 67 | config = yaml.load(f, Loader=yaml.FullLoader) 68 | model = RegNet_DropBlock(config) 69 | # print(model) 70 | last_checkpoint = '../pretrained_models/RegNetY-3.2GF_dds_8gpu.pyth' 71 | err_str = "Checkpoint '{}' not found" 72 | assert os.path.exists(last_checkpoint), err_str.format(last_checkpoint) 73 | checkpoint = torch.load(last_checkpoint, map_location="cpu") 74 | model.load_state_dict(checkpoint["model_state"]) 75 | print('have loaded checkpoint from {}'.format(last_checkpoint)) 76 | if pretrained is not None: 77 | settings = pretrained_settings['regnet'][pretrained] 78 | initialize_pretrained_model(model, num_classes, settings) 79 | return model 80 | 81 | 82 | def RegNetY_8_0_GF_DropBlock(num_classes=1000, pretrained='imagenet'): 83 | f = open('../lib/backbone/regnet_yaml/RegNetY-8.0GF_dds_8gpu.yaml') 84 | config = yaml.load(f, Loader=yaml.FullLoader) 85 | model = RegNet_DropBlock(config) 86 | # print(model) 87 | last_checkpoint = '../pretrained_models/RegNetY-8.0GF_dds_8gpu.pyth' 88 | err_str = "Checkpoint '{}' not found" 89 | assert os.path.exists(last_checkpoint), err_str.format(last_checkpoint) 90 | checkpoint = torch.load(last_checkpoint, map_location="cpu") 91 | model.load_state_dict(checkpoint["model_state"]) 92 | print('have loaded checkpoint from {}'.format(last_checkpoint)) 93 | if pretrained is not None: 94 | settings = pretrained_settings['regnet'][pretrained] 95 | initialize_pretrained_model(model, num_classes, settings) 96 | return model 97 | 98 | 99 | def RegNetY_1_6_0_GF_DropBlock(num_classes=1000, pretrained='imagenet'): 100 | f = open('../lib/backbone/regnet_yaml/RegNetY-16GF_dds_8gpu.yaml') 101 | config = yaml.load(f, Loader=yaml.FullLoader) 102 | model = RegNet_DropBlock(config) 103 | # print(model) 104 | last_checkpoint = '../pretrained_models/RegNetY-16GF_dds_8gpu.pyth' 105 | err_str = "Checkpoint '{}' not found" 106 | assert os.path.exists(last_checkpoint), err_str.format(last_checkpoint) 107 | checkpoint = torch.load(last_checkpoint, map_location="cpu") 108 | model.load_state_dict(checkpoint["model_state"]) 109 | print('have loaded checkpoint from {}'.format(last_checkpoint)) 110 | if pretrained is not None: 111 | settings = pretrained_settings['regnet'][pretrained] 112 | initialize_pretrained_model(model, num_classes, settings) 113 | return model 114 | 115 | 116 | if __name__ == "__main__": 117 | RegNetY_3_2_GF_DropBlock() 118 | print('success') 119 | 120 | -------------------------------------------------------------------------------- /lib/backbone/efficientnet.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | from efficientnet_pytorch import EfficientNet 3 | 4 | pretrained_settings = { 5 | 'efficientnet': { 6 | 'imagenet': { 7 | 'input_space': 'RGB', 8 | 'input_size': [3, 224, 224], 9 | 'input_range': [0, 1], 10 | 'mean': [0.485, 0.456, 0.406], 11 | 'std': [0.229, 0.224, 0.225], 12 | 'num_classes': 1000 13 | } 14 | }, 15 | } 16 | 17 | 18 | def initialize_pretrained_model(model, num_classes, settings): 19 | assert num_classes == settings['num_classes'],'num_classes should be {}, but is {}'.format( 20 | settings['num_classes'], num_classes) 21 | model.input_space = settings['input_space'] 22 | model.input_size = settings['input_size'] 23 | model.input_range = settings['input_range'] 24 | model.mean = settings['mean'] 25 | model.std = settings['std'] 26 | 27 | 28 | def efficientnet_b0(num_classes=1000, pretrained='imagenet'): 29 | model = EfficientNet.from_pretrained('efficientnet-b0', advprop=False) 30 | if pretrained is not None: 31 | settings = pretrained_settings['efficientnet'][pretrained] 32 | initialize_pretrained_model(model, num_classes, settings) 33 | return model 34 | 35 | 36 | def efficientnet_b1(num_classes=1000, pretrained='imagenet'): 37 | model = EfficientNet.from_pretrained('efficientnet-b1', advprop=False) 38 | if pretrained is not None: 39 | settings = pretrained_settings['efficientnet'][pretrained] 40 | initialize_pretrained_model(model, num_classes, settings) 41 | return model 42 | 43 | 44 | def efficientnet_b2(num_classes=1000, pretrained='imagenet'): 45 | model = EfficientNet.from_pretrained('efficientnet-b2', advprop=False) 46 | if pretrained is not None: 47 | settings = pretrained_settings['efficientnet'][pretrained] 48 | initialize_pretrained_model(model, num_classes, settings) 49 | return model 50 | 51 | 52 | def efficientnet_b3(num_classes=1000, pretrained='imagenet'): 53 | model = EfficientNet.from_pretrained('efficientnet-b3', advprop=False) 54 | if pretrained is not None: 55 | settings = pretrained_settings['efficientnet'][pretrained] 56 | initialize_pretrained_model(model, num_classes, settings) 57 | return model 58 | 59 | 60 | def efficientnet_b4(num_classes=1000, pretrained='imagenet'): 61 | model = EfficientNet.from_pretrained('efficientnet-b4', advprop=False) 62 | if pretrained is not None: 63 | settings = pretrained_settings['efficientnet'][pretrained] 64 | initialize_pretrained_model(model, num_classes, settings) 65 | return model 66 | 67 | 68 | def efficientnet_b5(num_classes=1000, pretrained='imagenet'): 69 | model = EfficientNet.from_pretrained('efficientnet-b5', advprop=False) 70 | if pretrained is not None: 71 | settings = pretrained_settings['efficientnet'][pretrained] 72 | initialize_pretrained_model(model, num_classes, settings) 73 | return model 74 | 75 | 76 | def efficientnet_b6(num_classes=1000, pretrained='imagenet'): 77 | model = EfficientNet.from_pretrained('efficientnet-b6', advprop=False) 78 | if pretrained is not None: 79 | settings = pretrained_settings['efficientnet'][pretrained] 80 | initialize_pretrained_model(model, num_classes, settings) 81 | return model 82 | 83 | 84 | def efficientnet_b7(num_classes=1000, pretrained='imagenet'): 85 | model = EfficientNet.from_pretrained('efficientnet-b7', advprop=False) 86 | if pretrained is not None: 87 | settings = pretrained_settings['efficientnet'][pretrained] 88 | initialize_pretrained_model(model, num_classes, settings) 89 | return model 90 | 91 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-1.6GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 18 6 | W0: 80 7 | WA: 34.01 8 | WM: 2.25 9 | GROUP_W: 24 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-12GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 19 6 | W0: 168 7 | WA: 73.36 8 | WM: 2.37 9 | GROUP_W: 112 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True 60 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-16GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 22 6 | W0: 216 7 | WA: 55.59 8 | WM: 2.1 9 | GROUP_W: 128 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True 60 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-200MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 13 6 | W0: 24 7 | WA: 36.44 8 | WM: 2.49 9 | GROUP_W: 8 10 | 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_ON: False 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | 25 | # universal parameter 26 | # ------------------------------------------------------------------------------------ # 27 | # AnyNet options: this part is not used in regnet 28 | # ------------------------------------------------------------------------------------ # 29 | ANYNET: 30 | # Stem type 31 | STEM_TYPE: "simple_stem_in" 32 | # Stem width 33 | STEM_W: 32 34 | # Block type 35 | BLOCK_TYPE: "res_bottleneck_block" 36 | # Depth for each stage (number of blocks in the stage) 37 | DEPTHS: [] 38 | # Width for each stage (width of each block in the stage) 39 | WIDTHS: [] 40 | # Strides for each stage (applies to the first block of each stage) 41 | STRIDES: [] 42 | # Bottleneck multipliers for each stage (applies to bottleneck block) 43 | BOT_MULS: [] 44 | # Group widths for each stage (applies to bottleneck block) 45 | GROUP_WS: [] 46 | # Whether SE is enabled for res_bottleneck_block 47 | SE_ON: False 48 | # SE ratio 49 | SE_R: 0.25 50 | 51 | # ------------------------------------------------------------------------------------ # 52 | # Batch norm options 53 | # ------------------------------------------------------------------------------------ # 54 | BN: 55 | EPS: 0.00001 56 | MOM: 0.1 57 | 58 | ## ------------------------------------------------------------------------------------ # 59 | ## Memory options 60 | ## ------------------------------------------------------------------------------------ # 61 | MEM: 62 | RELU_INPLACE: True 63 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-3.2GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 25 6 | W0: 88 7 | WA: 26.31 8 | WM: 2.25 9 | GROUP_W: 48 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-32GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 23 6 | W0: 320 7 | WA: 69.86 8 | WM: 2.0 9 | GROUP_W: 168 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True 60 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-4.0GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 23 6 | W0: 96 7 | WA: 38.65 8 | WM: 2.43 9 | GROUP_W: 40 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | 25 | # universal parameter 26 | # ------------------------------------------------------------------------------------ # 27 | # AnyNet options: this part is not used in regnet 28 | # ------------------------------------------------------------------------------------ # 29 | ANYNET: 30 | # Stem type 31 | STEM_TYPE: "simple_stem_in" 32 | # Stem width 33 | STEM_W: 32 34 | # Block type 35 | BLOCK_TYPE: "res_bottleneck_block" 36 | # Depth for each stage (number of blocks in the stage) 37 | DEPTHS: [] 38 | # Width for each stage (width of each block in the stage) 39 | WIDTHS: [] 40 | # Strides for each stage (applies to the first block of each stage) 41 | STRIDES: [] 42 | # Bottleneck multipliers for each stage (applies to bottleneck block) 43 | BOT_MULS: [] 44 | # Group widths for each stage (applies to bottleneck block) 45 | GROUP_WS: [] 46 | # Whether SE is enabled for res_bottleneck_block 47 | SE_ON: False 48 | # SE ratio 49 | SE_R: 0.25 50 | 51 | # ------------------------------------------------------------------------------------ # 52 | # Batch norm options 53 | # ------------------------------------------------------------------------------------ # 54 | BN: 55 | EPS: 0.00001 56 | MOM: 0.1 57 | ## ------------------------------------------------------------------------------------ # 58 | ## Memory options 59 | ## ------------------------------------------------------------------------------------ # 60 | MEM: 61 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-400MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 22 6 | W0: 24 7 | WA: 24.48 8 | WM: 2.54 9 | GROUP_W: 16 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | 25 | # universal parameter 26 | # ------------------------------------------------------------------------------------ # 27 | # AnyNet options: this part is not used in regnet 28 | # ------------------------------------------------------------------------------------ # 29 | ANYNET: 30 | # Stem type 31 | STEM_TYPE: "simple_stem_in" 32 | # Stem width 33 | STEM_W: 32 34 | # Block type 35 | BLOCK_TYPE: "res_bottleneck_block" 36 | # Depth for each stage (number of blocks in the stage) 37 | DEPTHS: [] 38 | # Width for each stage (width of each block in the stage) 39 | WIDTHS: [] 40 | # Strides for each stage (applies to the first block of each stage) 41 | STRIDES: [] 42 | # Bottleneck multipliers for each stage (applies to bottleneck block) 43 | BOT_MULS: [] 44 | # Group widths for each stage (applies to bottleneck block) 45 | GROUP_WS: [] 46 | # Whether SE is enabled for res_bottleneck_block 47 | SE_ON: False 48 | # SE ratio 49 | SE_R: 0.25 50 | 51 | # ------------------------------------------------------------------------------------ # 52 | # Batch norm options 53 | # ------------------------------------------------------------------------------------ # 54 | BN: 55 | EPS: 0.00001 56 | MOM: 0.1 57 | ## ------------------------------------------------------------------------------------ # 58 | ## Memory options 59 | ## ------------------------------------------------------------------------------------ # 60 | MEM: 61 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-6.4GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 17 6 | W0: 184 7 | WA: 60.83 8 | WM: 2.07 9 | GROUP_W: 56 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True 60 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-600MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 16 6 | W0: 48 7 | WA: 36.97 8 | WM: 2.24 9 | GROUP_W: 24 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-8.0GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 23 6 | W0: 80 7 | WA: 49.56 8 | WM: 2.88 9 | GROUP_W: 120 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True 60 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetX-800MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | DEPTH: 16 6 | W0: 56 7 | WA: 35.73 8 | WM: 2.28 9 | GROUP_W: 16 10 | #universal parameter 11 | STEM_TYPE: "simple_stem_in" 12 | ## Stem width 13 | STEM_W: 32 14 | ## Block type 15 | BLOCK_TYPE: "res_bottleneck_block" 16 | ## Stride of each stage 17 | STRIDE: 2 18 | ## Squeeze-and-Excitation (RegNetY) 19 | SE_ON: False 20 | ## Squeeze-and-Excitation (RegNetY) 21 | SE_R: 0.25 22 | ## Bottleneck multiplier (bm = 1 / b from the paper) 23 | BOT_MUL: 1.0 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options:this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-1.6GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 27 7 | W0: 48 8 | WA: 20.71 9 | WM: 2.65 10 | GROUP_W: 24 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-12GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 19 7 | W0: 168 8 | WA: 73.36 9 | WM: 2.37 10 | GROUP_W: 112 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True 61 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-16GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 18 7 | W0: 200 8 | WA: 106.23 9 | WM: 2.48 10 | GROUP_W: 112 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-200MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 13 7 | W0: 24 8 | WA: 36.44 9 | WM: 2.49 10 | GROUP_W: 8 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | # universal parameter 24 | # ------------------------------------------------------------------------------------ # 25 | # AnyNet options: this part is not used in regnet 26 | # ------------------------------------------------------------------------------------ # 27 | ANYNET: 28 | # Stem type 29 | STEM_TYPE: "simple_stem_in" 30 | # Stem width 31 | STEM_W: 32 32 | # Block type 33 | BLOCK_TYPE: "res_bottleneck_block" 34 | # Depth for each stage (number of blocks in the stage) 35 | DEPTHS: [] 36 | # Width for each stage (width of each block in the stage) 37 | WIDTHS: [] 38 | # Strides for each stage (applies to the first block of each stage) 39 | STRIDES: [] 40 | # Bottleneck multipliers for each stage (applies to bottleneck block) 41 | BOT_MULS: [] 42 | # Group widths for each stage (applies to bottleneck block) 43 | GROUP_WS: [] 44 | # Whether SE is enabled for res_bottleneck_block 45 | SE_ON: False 46 | # SE ratio 47 | SE_R: 0.25 48 | 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-3.2GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 21 7 | W0: 80 8 | WA: 42.63 9 | WM: 2.66 10 | GROUP_W: 24 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | # universal parameter 24 | # ------------------------------------------------------------------------------------ # 25 | # AnyNet options: this part is not used in regnet 26 | # ------------------------------------------------------------------------------------ # 27 | ANYNET: 28 | # Stem type 29 | STEM_TYPE: "simple_stem_in" 30 | # Stem width 31 | STEM_W: 32 32 | # Block type 33 | BLOCK_TYPE: "res_bottleneck_block" 34 | # Depth for each stage (number of blocks in the stage) 35 | DEPTHS: [] 36 | # Width for each stage (width of each block in the stage) 37 | WIDTHS: [] 38 | # Strides for each stage (applies to the first block of each stage) 39 | STRIDES: [] 40 | # Bottleneck multipliers for each stage (applies to bottleneck block) 41 | BOT_MULS: [] 42 | # Group widths for each stage (applies to bottleneck block) 43 | GROUP_WS: [] 44 | # Whether SE is enabled for res_bottleneck_block 45 | SE_ON: False 46 | # SE ratio 47 | SE_R: 0.25 48 | 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-32GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 20 7 | W0: 232 8 | WA: 115.89 9 | WM: 2.53 10 | GROUP_W: 232 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-4.0GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 22 7 | W0: 96 8 | WA: 31.41 9 | WM: 2.24 10 | GROUP_W: 64 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | # universal parameter 24 | # ------------------------------------------------------------------------------------ # 25 | # AnyNet options: this part is not used in regnet 26 | # ------------------------------------------------------------------------------------ # 27 | ANYNET: 28 | # Stem type 29 | STEM_TYPE: "simple_stem_in" 30 | # Stem width 31 | STEM_W: 32 32 | # Block type 33 | BLOCK_TYPE: "res_bottleneck_block" 34 | # Depth for each stage (number of blocks in the stage) 35 | DEPTHS: [] 36 | # Width for each stage (width of each block in the stage) 37 | WIDTHS: [] 38 | # Strides for each stage (applies to the first block of each stage) 39 | STRIDES: [] 40 | # Bottleneck multipliers for each stage (applies to bottleneck block) 41 | BOT_MULS: [] 42 | # Group widths for each stage (applies to bottleneck block) 43 | GROUP_WS: [] 44 | # Whether SE is enabled for res_bottleneck_block 45 | SE_ON: False 46 | # SE ratio 47 | SE_R: 0.25 48 | 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-400MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 16 7 | W0: 48 8 | WA: 27.89 9 | WM: 2.09 10 | GROUP_W: 8 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-6.4GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 25 7 | W0: 112 8 | WA: 33.22 9 | WM: 2.27 10 | GROUP_W: 72 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True 61 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-600MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 15 7 | W0: 48 8 | WA: 32.54 9 | WM: 2.32 10 | GROUP_W: 16 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | # universal parameter 24 | # ------------------------------------------------------------------------------------ # 25 | # AnyNet options: this part is not used in regnet 26 | # ------------------------------------------------------------------------------------ # 27 | ANYNET: 28 | # Stem type 29 | STEM_TYPE: "simple_stem_in" 30 | # Stem width 31 | STEM_W: 32 32 | # Block type 33 | BLOCK_TYPE: "res_bottleneck_block" 34 | # Depth for each stage (number of blocks in the stage) 35 | DEPTHS: [] 36 | # Width for each stage (width of each block in the stage) 37 | WIDTHS: [] 38 | # Strides for each stage (applies to the first block of each stage) 39 | STRIDES: [] 40 | # Bottleneck multipliers for each stage (applies to bottleneck block) 41 | BOT_MULS: [] 42 | # Group widths for each stage (applies to bottleneck block) 43 | GROUP_WS: [] 44 | # Whether SE is enabled for res_bottleneck_block 45 | SE_ON: False 46 | # SE ratio 47 | SE_R: 0.25 48 | 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-8.0GF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: true 6 | DEPTH: 17 7 | W0: 192 8 | WA: 76.82 9 | WM: 2.19 10 | GROUP_W: 56 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | 24 | # universal parameter 25 | # ------------------------------------------------------------------------------------ # 26 | # AnyNet options: this part is not used in regnet 27 | # ------------------------------------------------------------------------------------ # 28 | ANYNET: 29 | # Stem type 30 | STEM_TYPE: "simple_stem_in" 31 | # Stem width 32 | STEM_W: 32 33 | # Block type 34 | BLOCK_TYPE: "res_bottleneck_block" 35 | # Depth for each stage (number of blocks in the stage) 36 | DEPTHS: [] 37 | # Width for each stage (width of each block in the stage) 38 | WIDTHS: [] 39 | # Strides for each stage (applies to the first block of each stage) 40 | STRIDES: [] 41 | # Bottleneck multipliers for each stage (applies to bottleneck block) 42 | BOT_MULS: [] 43 | # Group widths for each stage (applies to bottleneck block) 44 | GROUP_WS: [] 45 | # Whether SE is enabled for res_bottleneck_block 46 | SE_ON: False 47 | # SE ratio 48 | SE_R: 0.25 49 | 50 | # ------------------------------------------------------------------------------------ # 51 | # Batch norm options 52 | # ------------------------------------------------------------------------------------ # 53 | BN: 54 | EPS: 0.00001 55 | MOM: 0.1 56 | ## ------------------------------------------------------------------------------------ # 57 | ## Memory options 58 | ## ------------------------------------------------------------------------------------ # 59 | MEM: 60 | RELU_INPLACE: True 61 | -------------------------------------------------------------------------------- /lib/backbone/regnet_yaml/RegNetY-800MF_dds_8gpu.yaml: -------------------------------------------------------------------------------- 1 | MODEL: 2 | TYPE: regnet 3 | NUM_CLASSES: 1000 4 | REGNET: 5 | SE_ON: True 6 | DEPTH: 14 7 | W0: 56 8 | WA: 38.84 9 | WM: 2.4 10 | GROUP_W: 16 11 | #universal parameter 12 | STEM_TYPE: "simple_stem_in" 13 | ## Stem width 14 | STEM_W: 32 15 | ## Block type 16 | BLOCK_TYPE: "res_bottleneck_block" 17 | ## Stride of each stage 18 | STRIDE: 2 19 | ## Squeeze-and-Excitation (RegNetY) 20 | SE_R: 0.25 21 | ## Bottleneck multiplier (bm = 1 / b from the paper) 22 | BOT_MUL: 1.0 23 | # universal parameter 24 | # ------------------------------------------------------------------------------------ # 25 | # AnyNet options: this part is not used in regnet 26 | # ------------------------------------------------------------------------------------ # 27 | ANYNET: 28 | # Stem type 29 | STEM_TYPE: "simple_stem_in" 30 | # Stem width 31 | STEM_W: 32 32 | # Block type 33 | BLOCK_TYPE: "res_bottleneck_block" 34 | # Depth for each stage (number of blocks in the stage) 35 | DEPTHS: [] 36 | # Width for each stage (width of each block in the stage) 37 | WIDTHS: [] 38 | # Strides for each stage (applies to the first block of each stage) 39 | STRIDES: [] 40 | # Bottleneck multipliers for each stage (applies to bottleneck block) 41 | BOT_MULS: [] 42 | # Group widths for each stage (applies to bottleneck block) 43 | GROUP_WS: [] 44 | # Whether SE is enabled for res_bottleneck_block 45 | SE_ON: False 46 | # SE ratio 47 | SE_R: 0.25 48 | 49 | # ------------------------------------------------------------------------------------ # 50 | # Batch norm options 51 | # ------------------------------------------------------------------------------------ # 52 | BN: 53 | EPS: 0.00001 54 | MOM: 0.1 55 | ## ------------------------------------------------------------------------------------ # 56 | ## Memory options 57 | ## ------------------------------------------------------------------------------------ # 58 | MEM: 59 | RELU_INPLACE: True -------------------------------------------------------------------------------- /lib/config/__init__.py: -------------------------------------------------------------------------------- 1 | from .default import _C as cfg 2 | from .default import update_config 3 | from .default import update_cfg_name -------------------------------------------------------------------------------- /lib/config/default.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | from yacs.config import CfgNode as CN 6 | 7 | _C = CN() 8 | 9 | # ----- BASIC SETTINGS ----- 10 | _C.NAME = "default" 11 | _C.OUTPUT_DIR = "./output/derm_7pt" 12 | _C.VALID_STEP = 5 13 | _C.SAVE_STEP = 5 14 | _C.SHOW_STEP = 20 15 | _C.PIN_MEMORY = True 16 | _C.INPUT_SIZE = (224, 224) # (h, w) 17 | _C.COLOR_SPACE = "RGB" 18 | _C.RESUME_MODEL = "" 19 | _C.RESUME_MODE = "all" 20 | _C.CPU_MODE = False 21 | _C.EVAL_MODE = False 22 | _C.GPUS = [0, 1] 23 | 24 | # ----- DATASET BUILDER ----- 25 | _C.DATASET = CN() 26 | _C.DATASET.DATASET = "" 27 | _C.DATASET.ROOT = "" 28 | _C.DATASET.DATA_TYPE = "jpg" 29 | _C.DATASET.TRAIN_JSON = "" 30 | _C.DATASET.VALID_JSON = "" 31 | _C.DATASET.TEST_JSON = "" 32 | _C.DATASET.CLASS_NAME = ['BCC', 'NV', 'MEL', 'MISC', 'SK'] 33 | _C.DATASET.VALID_ADD_ONE_CLASS = False # for ISIC_2019 valid and test, the number of class is increased from 8 to 9. 34 | _C.DATASET.ADD_CLASS_NAME = "UNK" 35 | _C.DATASET.IMBALANCECIFAR = CN() 36 | _C.DATASET.IMBALANCECIFAR.RATIO = 0.01 37 | _C.DATASET.IMBALANCECIFAR.RANDOM_SEED = 0 38 | 39 | # ----- BACKBONE BUILDER ----- 40 | _C.BACKBONE = CN() 41 | _C.BACKBONE.TYPE = "RegNetY_800MF" # refer to lib/backbone/all_models.py 42 | _C.BACKBONE.BBN = False 43 | _C.BACKBONE.FREEZE = False 44 | _C.BACKBONE.PRE_FREEZE = False 45 | _C.BACKBONE.PRE_FREEZE_EPOCH = 5 46 | _C.BACKBONE.PRETRAINED = True 47 | _C.BACKBONE.PRETRAINED_MODEL = "" 48 | 49 | # if using drop block, below are drop block parameter 50 | _C.BACKBONE.DROP = CN() 51 | _C.BACKBONE.DROP.BLOCK_PROB = 0.1 52 | _C.BACKBONE.DROP.BLOCK_SIZE = 5 53 | _C.BACKBONE.DROP.NR_STEPS = 50000 54 | # dropout parameter to the last FC layer 55 | _C.BACKBONE.DROP.OUT_PROB = 0.1 56 | 57 | # ----- MODULE BUILDER ----- 58 | _C.MODULE = CN() 59 | _C.MODULE.TYPE = "GAP" # "GAP", "Identity" 60 | 61 | # ----- CLASSIFIER BUILDER ----- 62 | _C.CLASSIFIER = CN() 63 | _C.CLASSIFIER.TYPE = "FC" # "FC", "FCNorm" 64 | _C.CLASSIFIER.BIAS = True 65 | 66 | # ----- LOSS BUILDER ----- 67 | _C.LOSS = CN() 68 | _C.LOSS.WEIGHT_POWER = 1.1 69 | _C.LOSS.EXTRA_WEIGHT = [1.0, 1.0, 1.0, 1.0, 1.0] 70 | _C.LOSS.LOSS_TYPE = "CrossEntropy" # "CrossEntropy", "LDAMLoss", "FocalLoss", "LOWLoss", "GHMCLoss", "CCELoss", "MWNLoss" 71 | _C.LOSS.SCHEDULER = "default" # "default"--the weights of all classes are "1.0", 72 | # "re_weight"--re-weighting by the power of inverse class frequency at all train stage, 73 | # "drw"--two-stage strategy using re-weighting at the second stage, 74 | # "cls"--cumulative learning strategy to set loss weight. 75 | # For drw scheduler 76 | _C.LOSS.DRW_EPOCH = 50 77 | # For cls scheduler 78 | _C.LOSS.CLS_EPOCH_MIN = 20 79 | _C.LOSS.CLS_EPOCH_MAX = 60 80 | 81 | # For LDAMLoss 82 | _C.LOSS.LDAM = CN() 83 | _C.LOSS.LDAM.MAX_MARGIN = 0.5 84 | # For FocalLoss 85 | _C.LOSS.FOCAL = CN() 86 | _C.LOSS.FOCAL.GAMMA = 2.0 87 | _C.LOSS.FOCAL.TYPE = "sigmoid" # "cross_entropy", "sigmoid", "ldam" 88 | _C.LOSS.FOCAL.SIGMOID = "normal" # "normal", "enlarge" 89 | # For LOWLoss 90 | _C.LOSS.LOW = CN() 91 | _C.LOSS.LOW.LAMB = 0.01 92 | # For GHMCLoss 93 | _C.LOSS.GHMC = CN() 94 | _C.LOSS.GHMC.BINS = 10 95 | _C.LOSS.GHMC.MOMENTUM = 0.0 96 | # For MWNLoss 97 | _C.LOSS.MWNL = CN() 98 | _C.LOSS.MWNL.GAMMA = 2.0 99 | _C.LOSS.MWNL.BETA = 0.1 100 | _C.LOSS.MWNL.TYPE = "fix" # "zero", "fix", "decrease" 101 | _C.LOSS.MWNL.SIGMOID = "normal" # "normal", "enlarge" 102 | 103 | # ----- TRAIN BUILDER ----- 104 | _C.TRAIN = CN() 105 | _C.TRAIN.BATCH_SIZE = 32 # for every gpu 106 | _C.TRAIN.MAX_EPOCH = 70 107 | _C.TRAIN.SHUFFLE = True 108 | _C.TRAIN.NUM_WORKERS = 8 109 | _C.TRAIN.TENSORBOARD = CN() 110 | _C.TRAIN.TENSORBOARD.ENABLE = True 111 | 112 | # ----- SAMPLER BUILDER ----- 113 | _C.TRAIN.SAMPLER = CN() 114 | _C.TRAIN.SAMPLER.TYPE = "default" # "default", "weighted sampler", "oversample" 115 | _C.TRAIN.SAMPLER.IMAGE_TYPE = "derm" # "derm", "clinic". For derm_7pt dataset used. 116 | 117 | _C.TRAIN.SAMPLER.BORDER_CROP = "pixel" # "pixel", "ratio" 118 | _C.TRAIN.SAMPLER.BORDER_CROP_PIXEL = 0 # An integer specifying how many pixels to crop at the image border. Useful if images contain a black boundary. 119 | _C.TRAIN.SAMPLER.BORDER_CROP_RATIO = 0.0 # the ratio of edge of the image to be cropped. 120 | _C.TRAIN.SAMPLER.IMAGE_RESIZE = True # whether the input image needs to be resized to a fix size 121 | _C.TRAIN.SAMPLER.IMAGE_RESIZE_SHORT = 450 # the need size of the short side of the input image 122 | _C.TRAIN.SAMPLER.COLOR_CONSTANCY = False 123 | _C.TRAIN.SAMPLER.CONSTANCY_POWER = 6.0 124 | _C.TRAIN.SAMPLER.CONSTANCY_GAMMA = 0.0 125 | 126 | # For Modified RandAugment 127 | _C.TRAIN.SAMPLER.AUGMENT = CN() 128 | _C.TRAIN.SAMPLER.AUGMENT.NEED_AUGMENT = False 129 | _C.TRAIN.SAMPLER.AUGMENT.AUG_METHOD = "v1_0" # the method of Modified RandAugment ('v0_0' to 'v3_1') or RandAugment ('rand') (refer to: lib/data_transform/modified_randaugment.py) 130 | _C.TRAIN.SAMPLER.AUGMENT.AUG_PROB = 0.7 # the probability parameter 'P' of Modified RandAugment (0.1 -- 0.9) 131 | _C.TRAIN.SAMPLER.AUGMENT.AUG_MAG = 10 # the magnitude parameter 'M' of Modified RandAugment (1 -- 20) 132 | _C.TRAIN.SAMPLER.AUGMENT.AUG_LAYER_NUM = 1 # the number of transformations applied to a training image if AUG_METHOD = 'rand' 133 | 134 | # for BBN sampler 135 | _C.TRAIN.SAMPLER.DUAL_SAMPLER = CN() 136 | _C.TRAIN.SAMPLER.DUAL_SAMPLER.TYPE = "reversed" # "balance", "reverse", "uniform" 137 | # for other sampler 138 | _C.TRAIN.SAMPLER.WEIGHTED_SAMPLER = CN() 139 | _C.TRAIN.SAMPLER.WEIGHTED_SAMPLER.TYPE = "balance" # "balance", "reverse" 140 | 141 | # for multi crop 142 | _C.TRAIN.SAMPLER.MULTI_CROP = CN() 143 | _C.TRAIN.SAMPLER.MULTI_CROP.ENABLE = False # Should the crops be order or random for evaluation 144 | _C.TRAIN.SAMPLER.MULTI_CROP.CROP_NUM = 16 # Number of crops to use during evaluation (must be N^2) 145 | _C.TRAIN.SAMPLER.MULTI_CROP.L_REGION = 1.0 # Only crop within a certain range of the central area (along the long side of the image) 146 | _C.TRAIN.SAMPLER.MULTI_CROP.S_REGION = 1.0 # Only crop within a certain range of the central area (along the short side of the image) 147 | _C.TRAIN.SAMPLER.MULTI_CROP.SCHEME = 'average' # Averaging or voting over the crop predictions ("vote", "average") 148 | # for multi transformation of the center crop 149 | _C.TRAIN.SAMPLER.MULTI_SCALE = CN() 150 | _C.TRAIN.SAMPLER.MULTI_SCALE.ENABLE = False # whether to perform multi transformation on the central crop 151 | _C.TRAIN.SAMPLER.MULTI_SCALE.SCALE_NUM = 12 # Number of scales to use during evaluation (must be less than or equal to the length of SCALE_NAME) 152 | _C.TRAIN.SAMPLER.MULTI_SCALE.SCALE_NAME = ["scale_+00", "flip_x_+00", "rotate_90_+00", "rotate_270_+00", 153 | "scale_+10", "flip_x_+10", "rotate_90_+10", "rotate_270_+10", 154 | "scale_+20", "flip_x_+20", "rotate_90_+20", "rotate_270_+20", 155 | "scale_+30", "flip_x_+30", "rotate_90_+30", "rotate_270_+30", 156 | "scale_-10", "flip_x_-10", "rotate_90_-10", "rotate_270_-10", 157 | "flip_y_+00", "flip_y_+10", "flip_y_-10", "flip_y_+20"] 158 | 159 | _C.TRAIN.SAMPLER.FIX_MEAN_VAR = CN() 160 | _C.TRAIN.SAMPLER.FIX_MEAN_VAR.ENABLE = True # Normalize using the mean and variance of each image, or using fixed values 161 | # A fixed set mean (input image will be subtracted from the mean, processing variance) 162 | _C.TRAIN.SAMPLER.FIX_MEAN_VAR.SET_MEAN = [0.485, 0.456, 0.406] 163 | # A fixed set variance 164 | _C.TRAIN.SAMPLER.FIX_MEAN_VAR.SET_VAR = [0.229, 0.224, 0.225] 165 | 166 | # ----- OPTIMIZER ----- 167 | _C.TRAIN.OPTIMIZER = CN() 168 | _C.TRAIN.OPTIMIZER.TYPE = "SGD" # 'SGD', 'ADAM', 'NADAM', 'RMSPROP' 169 | _C.TRAIN.OPTIMIZER.BASE_LR = 0.001 170 | _C.TRAIN.OPTIMIZER.MOMENTUM = 0.9 171 | _C.TRAIN.OPTIMIZER.WEIGHT_DECAY = 1e-4 172 | 173 | # ----- LR_SCHEDULER ----- 174 | _C.TRAIN.LR_SCHEDULER = CN() 175 | _C.TRAIN.LR_SCHEDULER.TYPE = "multistep" # "steplr", "multistep", "cosine", "warmup" 176 | _C.TRAIN.LR_SCHEDULER.LR_LOWER_STEP = 20 # for 'steplr' 177 | _C.TRAIN.LR_SCHEDULER.LR_STEP = [40, 50] # for 'multistep' 178 | _C.TRAIN.LR_SCHEDULER.LR_FACTOR = 0.1 179 | _C.TRAIN.LR_SCHEDULER.WARM_EPOCH = 5 # for 'warmup' 180 | _C.TRAIN.LR_SCHEDULER.COSINE_DECAY_END = 0 181 | 182 | # For valid or test 183 | _C.TEST = CN() 184 | _C.TEST.BATCH_SIZE = 128 # for every gpu 185 | _C.TEST.NUM_WORKERS = 8 186 | _C.TEST.MODEL_FILE = "best_model.pth" 187 | 188 | 189 | def update_config(cfg, args): 190 | cfg.defrost() 191 | cfg.merge_from_file(args.cfg) 192 | cfg.merge_from_list(args.opts) 193 | cfg.freeze() 194 | 195 | 196 | def update_cfg_name(cfg): 197 | ''' 198 | modify the cfg.NAME 199 | :param cfg: 200 | :return: 201 | ''' 202 | cfg.defrost() 203 | cfg_name = cfg.DATASET.DATASET + "." + cfg.BACKBONE.TYPE + ( 204 | "_BBN." if cfg.BACKBONE.BBN else ".") + cfg.LOSS.LOSS_TYPE + cfg.NAME 205 | cfg.merge_from_list(['NAME', cfg_name]) 206 | cfg.freeze() 207 | -------------------------------------------------------------------------------- /lib/core/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | -------------------------------------------------------------------------------- /lib/core/combiner.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from .evaluate import accuracy 3 | 4 | 5 | class Combiner: 6 | def __init__(self, cfg, device, model, loss_func): 7 | self.cfg = cfg 8 | if cfg.BACKBONE.BBN: 9 | self.type = "bbn_mix" 10 | else: 11 | self.type = "default" 12 | self.device = device 13 | self.epoch = 0 14 | self.max_epoch = cfg.TRAIN.MAX_EPOCH 15 | self.model = model 16 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 17 | self.func = torch.nn.Sigmoid() 18 | else: 19 | self.func = torch.nn.Softmax(dim=1) 20 | self.loss_func = loss_func 21 | self.alpha = 0.2 22 | self.div_epoch = self.max_epoch 23 | self.pre_freeze = self.cfg.BACKBONE.PRE_FREEZE 24 | 25 | def reset_epoch(self, epoch): 26 | self.epoch = epoch 27 | self.loss_func.reset_epoch(epoch) 28 | 29 | # Freeze the update of the model parameters first, 30 | # and then release it after a certain epoch. 31 | if self.pre_freeze and epoch > self.cfg.BACKBONE.PRE_FREEZE_EPOCH: 32 | self.pre_freeze = False 33 | if self.device == torch.device("cpu"): 34 | self.model.unfreeze_backbone() 35 | else: 36 | self.model.module.unfreeze_backbone() 37 | 38 | def forward(self, image, label, meta, **kwargs): 39 | return eval("self.{}".format(self.type))( 40 | image, label, meta, **kwargs 41 | ) 42 | 43 | def default(self, image, label, meta, **kwargs): 44 | image, label = image.to(self.device), label.to(self.device) 45 | output = self.model(image) 46 | if self.model.training or not self.cfg.DATASET.VALID_ADD_ONE_CLASS: 47 | loss = self.loss_func(output, label) 48 | else: 49 | loss = torch.zeros(1) # for isic_2019 valid and test, ignore "loss" 50 | now_pred = self.func(output) 51 | now_result = torch.argmax(now_pred, 1) 52 | now_acc, _ = accuracy(now_result.cpu().numpy(), label.cpu().numpy()) 53 | 54 | return loss, now_acc, now_pred 55 | 56 | # BBN method, please see the paper: "BBN: Bilateral-Branch Network with 57 | # Cumulative Learning for Long-Tailed Visual Recognition" 58 | def bbn_mix(self, image, label, meta, **kwargs): 59 | if self.model.training: 60 | image_a, image_b = image.to(self.device), meta["sample_image"].to(self.device) 61 | label_a, label_b = label.to(self.device), meta["sample_label"].to(self.device) 62 | 63 | feature_a, feature_b = ( 64 | self.model(image_a, feature_cb=True), 65 | self.model(image_b, feature_rb=True), 66 | ) 67 | 68 | if self.epoch < self.div_epoch: 69 | l = 1 - ((self.epoch - 1) / self.div_epoch) ** 2 # parabolic decay 70 | else: 71 | l = 0.0 72 | 73 | mixed_feature = 2 * torch.cat((l * feature_a, (1 - l) * feature_b), dim=1) 74 | output = self.model(mixed_feature, classifier_flag=True) 75 | loss = l * self.loss_func(output, label_a) + (1 - l) * self.loss_func(output, label_b) 76 | now_pred = self.func(output) 77 | now_result = torch.argmax(now_pred, 1) 78 | now_acc = ( 79 | l * accuracy(now_result.cpu().numpy(), label_a.cpu().numpy())[0] 80 | + (1 - l) * accuracy(now_result.cpu().numpy(), label_b.cpu().numpy())[0] 81 | ) 82 | else: 83 | image, label = image.to(self.device), label.to(self.device) 84 | feature = self.model(image, feature_flag=True) 85 | output = self.model(feature, classifier_flag=True) 86 | if not self.cfg.DATASET.VALID_ADD_ONE_CLASS: 87 | loss = self.loss_func(output, label) 88 | else: 89 | loss = torch.zeros(1) # ignore "loss" 90 | now_pred = self.func(output) 91 | now_result = torch.argmax(now_pred, 1) 92 | now_acc, _ = accuracy(now_result.cpu().numpy(), label.cpu().numpy()) 93 | 94 | return loss, now_acc, now_pred 95 | -------------------------------------------------------------------------------- /lib/core/evaluate.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from matplotlib import pyplot as plt 3 | 4 | 5 | class AverageMeter(object): 6 | """Computes and stores the average and current value""" 7 | 8 | def __init__(self): 9 | self.reset() 10 | 11 | def reset(self): 12 | self.val = 0 13 | self.avg = 0 14 | self.sum = 0 15 | self.count = 0 16 | 17 | def update(self, val, n=1): 18 | self.val = val 19 | self.sum += val * n 20 | self.count += n 21 | self.avg = self.sum / self.count if self.count != 0 else 0 22 | 23 | 24 | class FusionMatrix(object): 25 | def __init__(self, num_classes): 26 | self.num_classes = num_classes 27 | self.matrix = np.zeros((self.num_classes, self.num_classes), dtype=int) 28 | 29 | def update(self, output, label): 30 | length = output.shape[0] 31 | for i in range(length): 32 | self.matrix[int(output[i]), int(label[i])] += 1 33 | 34 | def get_fusion_matrix(self): 35 | return self.matrix 36 | 37 | def get_rec_per_class(self): 38 | rec = np.array( 39 | [ 40 | self.matrix[i, i] / self.matrix[:, i].sum() 41 | for i in range(self.num_classes) 42 | ] 43 | ) 44 | rec[np.isnan(rec)] = 0 45 | return rec 46 | 47 | def get_pre_per_class(self): 48 | pre = np.array( 49 | [ 50 | self.matrix[i, i] / self.matrix[i, :].sum() 51 | for i in range(self.num_classes) 52 | ] 53 | ) 54 | pre[np.isnan(pre)] = 0 55 | return pre 56 | 57 | def get_accuracy(self): 58 | acc = ( 59 | np.sum([self.matrix[i, i] for i in range(self.num_classes)]) 60 | / self.matrix.sum() 61 | ) 62 | return acc 63 | 64 | # convert multi-classification into binary classification tasks, and calculate the accuracy. 65 | def get_binary_accuracy(self, class_no): 66 | class_no = int(class_no) 67 | if class_no >= self.num_classes or class_no < 0: 68 | raise AttributeError( 69 | "Parameter class_no must less than the number of class.") 70 | 71 | error_num = 0 72 | for i in range(self.num_classes): 73 | error_num += self.matrix[i, class_no] 74 | error_num += self.matrix[class_no, i] 75 | error_num -= 2 * self.matrix[class_no, class_no] 76 | ok_num = self.matrix.sum() - error_num 77 | acc = ok_num / self.matrix.sum() 78 | return acc 79 | 80 | def get_balance_accuracy(self): 81 | rec = self.get_rec_per_class() 82 | bacc = np.mean(rec) 83 | return bacc 84 | 85 | def get_f1_score(self): 86 | recall = self.get_rec_per_class() 87 | precision = self.get_pre_per_class() 88 | f1_score = 2 * (precision * recall) / (precision + recall) 89 | f1_score[np.isnan(f1_score)] = 0 90 | return np.mean(f1_score) 91 | 92 | def plot_confusion_matrix(self, normalize = False, cmap=plt.cm.Blues): 93 | if normalize: 94 | title = 'Normalized confusion matrix' 95 | else: 96 | title = 'Confusion matrix, without normalization' 97 | 98 | # Compute confusion matrix 99 | cm = self.matrix.T 100 | 101 | fig, ax = plt.subplots() 102 | im = ax.imshow(cm, interpolation='nearest', cmap=cmap) 103 | ax.figure.colorbar(im, ax=ax) 104 | # We want to show all ticks... 105 | ax.set(xticks=np.arange(cm.shape[1]), 106 | yticks=np.arange(cm.shape[0]), 107 | # ... and label them with the respective list entries 108 | xticklabels=np.arange(self.num_classes), yticklabels=np.arange(self.num_classes), 109 | title=title, 110 | ylabel='True label', 111 | xlabel='Predicted label') 112 | 113 | # Rotate the tick labels and set their alignment. 114 | plt.setp(ax.get_xticklabels(), rotation=45, ha="right", 115 | rotation_mode="anchor") 116 | 117 | # Loop over data dimensions and create text annotations. 118 | fmt = '.2f' if normalize else 'd' 119 | thresh = cm.max() / 2. 120 | for i in range(cm.shape[0]): 121 | for j in range(cm.shape[1]): 122 | ax.text(j, i, format(cm[i, j], fmt), 123 | ha="center", va="center", 124 | color="white" if cm[i, j] > thresh else "black") 125 | fig.tight_layout() 126 | return fig 127 | 128 | 129 | def accuracy(output, label): 130 | cnt = label.shape[0] 131 | true_count = (output == label).sum() 132 | now_accuracy = true_count / cnt 133 | return now_accuracy, cnt 134 | -------------------------------------------------------------------------------- /lib/core/function.py: -------------------------------------------------------------------------------- 1 | from .evaluate import AverageMeter, FusionMatrix 2 | import numpy as np 3 | import torch 4 | from torch.nn import functional as F 5 | import time 6 | from sklearn.metrics import auc, roc_curve 7 | 8 | 9 | def train_model( 10 | train_loader, epoch, epoch_number, optimizer, 11 | combiner, cfg, logger, **kwargs 12 | ): 13 | if cfg.EVAL_MODE: 14 | combiner.model.eval() 15 | else: 16 | combiner.model.train() 17 | 18 | combiner.reset_epoch(epoch) 19 | 20 | start_time = time.time() 21 | all_loss = AverageMeter() 22 | acc = AverageMeter() 23 | for i, (image, label, meta) in enumerate(train_loader): 24 | cnt = label.shape[0] 25 | loss, now_acc, _ = combiner.forward(image, label, meta) 26 | 27 | optimizer.zero_grad() 28 | loss.backward() 29 | optimizer.step() 30 | 31 | all_loss.update(loss.data.item(), cnt) 32 | acc.update(now_acc, cnt) 33 | 34 | end_time = time.time() 35 | pbar_str = "---Epoch:{:>3d}/{} l_rate:{:>9.7f} Avg_Loss:{:>6.4f} Epoch_Acc:{:>6.3f}% Epoch_Time:{:>5.2f}min---".format( 36 | epoch, epoch_number, optimizer.param_groups[0]['lr'], all_loss.avg, acc.avg * 100, (end_time - start_time) / 60 37 | ) 38 | logger.info(pbar_str) 39 | return acc.avg, all_loss.avg 40 | 41 | 42 | def valid_model( 43 | val_loader, epoch, combiner, cfg, logger, **kwargs 44 | ): 45 | combiner.model.eval() 46 | 47 | num_classes = val_loader.dataset.get_num_classes() 48 | fusion_matrix = FusionMatrix(num_classes) 49 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 50 | num_classes = val_loader.dataset.get_num_classes() - 1 51 | 52 | all_preds = np.zeros([val_loader.dataset.get_num_images(), num_classes]) 53 | all_labels = np.zeros(val_loader.dataset.get_num_images()) 54 | ii = 0 55 | with torch.no_grad(): 56 | all_loss = AverageMeter() 57 | for i, (image, label, meta) in enumerate(val_loader): 58 | cnt = label.shape[0] 59 | loss, now_acc, now_pred = combiner.forward(image, label, meta) 60 | now_pred = now_pred.cpu().numpy() 61 | new_pred, new_label = get_val_result(now_pred, label.cpu().numpy(), cfg, num_classes) 62 | 63 | all_preds[ii:ii + new_pred.shape[0], :] = new_pred 64 | all_labels[ii:ii + new_pred.shape[0]] = new_label 65 | ii += new_pred.shape[0] 66 | all_loss.update(loss.data.item(), cnt) 67 | 68 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 69 | all_max = 1.0 - np.amax(all_preds, axis=1) 70 | all_preds = np.c_[all_preds, all_max] 71 | 72 | all_result = np.argmax(all_preds, 1) 73 | fusion_matrix.update(all_result, all_labels) 74 | roc_auc = get_roc_auc(all_preds, all_labels) 75 | 76 | metrics = {} 77 | metrics["loss"] = all_loss.avg 78 | metrics["sensitivity"] = fusion_matrix.get_rec_per_class() 79 | metrics["specificity"] = fusion_matrix.get_pre_per_class() 80 | metrics["f1_score"] = fusion_matrix.get_f1_score() 81 | metrics["roc_auc"] = roc_auc 82 | metrics["fusion_matrix"] = fusion_matrix.matrix 83 | if cfg.DATASET.DATASET == "isic_2017": 84 | auc_mean = (metrics["roc_auc"][0] + metrics["roc_auc"][1]) / 2.0 85 | else: 86 | auc_mean = np.mean(metrics["roc_auc"]) 87 | metrics["acc"] = fusion_matrix.get_accuracy() 88 | metrics["bacc"] = fusion_matrix.get_balance_accuracy() 89 | spec_mean = np.mean(metrics["specificity"]) 90 | 91 | logger.info("------- Valid: Epoch: {:>3d} Valid_Loss: {:>6.4f} Valid_Acc: {:>6.3f}% -------".format( 92 | epoch, metrics["loss"], metrics["acc"] * 100) 93 | ) 94 | logger.info(" roc_auc.mean: {:>6.3f} f1_score: {:>6.4f} Balance_Acc: {:>6.3f}% ".format( 95 | auc_mean, metrics["f1_score"], metrics["bacc"] * 100) 96 | ) 97 | logger.info(" roc_auc: {} ".format(metrics["roc_auc"])) 98 | logger.info(" sensitivity: {} ".format(metrics["sensitivity"])) 99 | logger.info(" specificity: {} mean: {} ".format(metrics["specificity"], spec_mean)) 100 | logger.info(" fusion_matrix: \n{} ".format(metrics["fusion_matrix"])) 101 | 102 | return metrics 103 | 104 | 105 | def get_val_result(pred, label, cfg, num_classes): 106 | val_sample_repeat_num = 0 107 | if cfg.TRAIN.SAMPLER.MULTI_CROP.ENABLE: 108 | val_sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_CROP.CROP_NUM 109 | if cfg.TRAIN.SAMPLER.MULTI_SCALE.ENABLE: 110 | val_sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_SCALE.SCALE_NUM 111 | 112 | if val_sample_repeat_num > 0: 113 | pred = pred.reshape(-1, val_sample_repeat_num, num_classes) 114 | pred = np.transpose(pred, (0, 2, 1)) 115 | label = label.reshape(-1, val_sample_repeat_num) 116 | label = label[:, 0] 117 | 118 | if cfg.TRAIN.SAMPLER.MULTI_CROP.SCHEME == 'vote': 119 | pred = np.argmax(pred, 1) 120 | predictions = np.zeros([pred.shape[0], num_classes]) 121 | for j in range(pred.shape[0]): 122 | predictions[j, :] = np.bincount(pred[j, :], minlength=num_classes) 123 | predictions[j, :] = predictions[j, :] / np.sum(predictions[j, :]) # normalize 124 | else: # 'average' 125 | predictions = np.mean(pred, 2) 126 | else: 127 | predictions = pred 128 | 129 | return predictions, label 130 | 131 | 132 | def get_test_result(pred, cfg, num_classes): 133 | val_sample_repeat_num = 0 134 | if cfg.TRAIN.SAMPLER.MULTI_CROP.ENABLE: 135 | val_sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_CROP.CROP_NUM 136 | if cfg.TRAIN.SAMPLER.MULTI_SCALE.ENABLE: 137 | val_sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_SCALE.SCALE_NUM 138 | 139 | if val_sample_repeat_num > 0: 140 | pred = pred.reshape(-1, val_sample_repeat_num, num_classes) 141 | pred = np.transpose(pred, (0, 2, 1)) 142 | 143 | if cfg.TRAIN.SAMPLER.MULTI_CROP.SCHEME == 'vote': 144 | pred = np.argmax(pred, 1) 145 | predictions = np.zeros([pred.shape[0], num_classes]) 146 | for j in range(pred.shape[0]): 147 | predictions[j, :] = np.bincount(pred[j, :], minlength=num_classes) 148 | predictions[j, :] = predictions[j, :] / np.sum(predictions[j, :]) # normalize 149 | else: # 'average' 150 | predictions = np.mean(pred, 2) 151 | else: 152 | predictions = pred 153 | 154 | return predictions 155 | 156 | 157 | def get_roc_auc(all_preds, all_labels): 158 | one_hot = label_to_one_hot(all_labels, all_preds.shape[1]) 159 | 160 | fpr = {} 161 | tpr = {} 162 | roc_auc = np.zeros([all_preds.shape[1]]) 163 | for i in range(all_preds.shape[1]): 164 | fpr[i], tpr[i], _ = roc_curve(one_hot[:, i], all_preds[:, i]) 165 | roc_auc[i] = auc(fpr[i], tpr[i]) 166 | 167 | return roc_auc 168 | 169 | 170 | def label_to_one_hot(label, num_class): 171 | one_hot = F.one_hot(torch.from_numpy(label).long(), num_class).float() 172 | one_hot = one_hot.numpy() 173 | 174 | return one_hot 175 | 176 | -------------------------------------------------------------------------------- /lib/data_transform/__init__.py: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /lib/data_transform/color_constancy.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import numpy 3 | import cv2 4 | 5 | 6 | def color_constancy(img, power=6, gamma=None): 7 | """ 8 | Parameters 9 | ---------- 10 | img: 2D numpy array 11 | The original image with format of (h, w, c) 12 | power: int 13 | The degree of norm, 6 is used in reference paper 14 | gamma: float 15 | The value of gamma correction, 2.2 is used in reference paper 16 | """ 17 | img_dtype = img.dtype 18 | 19 | if gamma is not None: 20 | img = img.astype('uint8') 21 | look_up_table = numpy.ones((256, 1), dtype='uint8') * 0 22 | for i in range(256): 23 | look_up_table[i][0] = 255 * pow(i / 255, 1 / gamma) 24 | img = cv2.LUT(img, look_up_table) 25 | img = img.astype('float32') 26 | img_power = numpy.power(img, power) 27 | rgb_vec = numpy.power(numpy.mean(img_power, (0, 1)), 1 / power) 28 | rgb_norm = numpy.sqrt(numpy.sum(numpy.power(rgb_vec, 2.0))) 29 | rgb_vec = rgb_vec / rgb_norm 30 | rgb_vec = 1 / (rgb_vec * numpy.sqrt(3)) 31 | img = numpy.multiply(img, rgb_vec) 32 | return img.astype(img_dtype) 33 | 34 | 35 | if __name__ == '__main__': 36 | im_org = cv2.imread("ISIC_0033078.jpg") 37 | im_cal = color_constancy(im_org, 6) 38 | cv2.imshow("ori", im_org) 39 | cv2.imshow("revise", im_cal) 40 | cv2.waitKey() 41 | cv2.destroyAllWindows() 42 | -------------------------------------------------------------------------------- /lib/data_transform/transforms.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import numpy as np 4 | from skimage.filters import gaussian 5 | import torch 6 | from PIL import Image 7 | from .color_constancy import color_constancy 8 | 9 | 10 | class RandomVerticalFlip(object): 11 | def __call__(self, img): 12 | if random.random() < 0.5: 13 | return img.transpose(Image.FLIP_TOP_BOTTOM) 14 | return img 15 | 16 | 17 | class DeNormalize(object): 18 | def __init__(self, mean, std): 19 | self.mean = mean 20 | self.std = std 21 | 22 | def __call__(self, tensor): 23 | for t, m, s in zip(tensor, self.mean, self.std): 24 | t.mul_(s).add_(m) 25 | return tensor 26 | 27 | 28 | class MaskToTensor(object): 29 | def __call__(self, img): 30 | return torch.from_numpy(np.array(img, dtype=np.int32)).long() 31 | 32 | 33 | class MaskToTensor_uint8(object): 34 | def __call__(self, img): 35 | return torch.from_numpy(np.array(img, dtype=np.uint8)) 36 | 37 | 38 | class MaskToTensor_float(object): 39 | def __call__(self, img): 40 | return torch.from_numpy(np.array(img, dtype=np.int32)).float() 41 | 42 | 43 | class FreeScale(object): 44 | """Resize the image to a fixed size, and keep the horizontal and vertical ratio unchanged 45 | size:(h, w), the values to which the sides of the image is resized 46 | """ 47 | def __init__(self, size, interpolation=Image.BILINEAR): 48 | self.size = size # size: (h, w) 49 | self.interpolation = interpolation 50 | 51 | def __call__(self, img): 52 | size_y = self.size[0] 53 | size_x = self.size[1] 54 | scale_y = img.size[1] / size_y 55 | scale_x = img.size[0] / size_x 56 | if scale_y < scale_x: # select the smaller value 57 | size_x = int(img.size[0] / scale_y) 58 | else: 59 | size_y = int(img.size[1] / scale_x) 60 | return img.resize((size_x, size_y), self.interpolation) 61 | 62 | 63 | class RandomCropInRate(object): 64 | """ random crop 65 | nsize: crop size 66 | rand_rate: The allowed region close to the center of the image for random cropping. (value: 0.7-1.0) 67 | """ 68 | def __init__(self, nsize, rand_rate=(1.0, 1.0)): 69 | self.nsize = nsize 70 | self.rand_rate = rand_rate # rand_rate: (l, s) 71 | 72 | def __call__(self, image): 73 | image_height = image.size[1] 74 | image_width = image.size[0] 75 | new_height = self.nsize[0] 76 | new_width = self.nsize[1] 77 | 78 | if image_width >= image_height: 79 | x_l = int(image_width * (1.0 - self.rand_rate[0]) / 2) 80 | x_r = int(image_width - x_l) - new_width 81 | y_l = int(image_height * (1.0 - self.rand_rate[1]) / 2) 82 | y_r = int(image_height - y_l) - new_height 83 | else: 84 | x_l = int(image_width * (1.0 - self.rand_rate[1]) / 2) 85 | x_r = int(image_width - x_l) - new_width 86 | y_l = int(image_height * (1.0 - self.rand_rate[0]) / 2) 87 | y_r = int(image_height - y_l) - new_height 88 | if x_r <= x_l or y_r <= y_l: 89 | raise ValueError('Invalid rand_rate: {}'.format(self.rand_rate)) 90 | 91 | if 0 < new_height < image_height: 92 | start_h = random.randint(y_l, y_r) 93 | else: 94 | start_h = 0 95 | new_height = image_height 96 | if 0 < new_width < image_width: 97 | start_w = random.randint(x_l, x_r) 98 | else: 99 | start_w = 0 100 | new_width = image_width 101 | image = np.array(image) 102 | image = image[start_h:start_h + new_height, start_w:start_w + new_width, :] 103 | return Image.fromarray(image.astype(np.uint8)) 104 | 105 | 106 | class FlipChannels(object): 107 | def __call__(self, img): 108 | img = np.array(img)[:, :, ::-1] 109 | return Image.fromarray(img.astype(np.uint8)) 110 | 111 | 112 | class RandomGaussianBlur(object): 113 | def __call__(self, img): 114 | sigma = 0.15 + random.random() * 1.15 115 | blurred_img = gaussian(np.array(img), sigma=sigma, multichannel=True) 116 | blurred_img *= 255 117 | return Image.fromarray(blurred_img.astype(np.uint8)) 118 | 119 | 120 | class NormalizePerImage(object): 121 | def __call__(self, tensor): 122 | """ 123 | Normalize with the mean and variance of each image, not all images' 124 | Args: 125 | tensor (Tensor): Tensor image of size (C, H, W) to be normalized. 126 | 127 | Returns: 128 | Tensor: Normalized Tensor image. 129 | """ 130 | if not (torch.is_tensor(tensor) and tensor.ndimension() == 3): 131 | raise TypeError('tensor is not a torch image.') 132 | 133 | mean = torch.mean(tensor, (1, 2)) 134 | for t, m in zip(tensor, mean): 135 | t.sub_(m) 136 | return tensor 137 | 138 | 139 | class ColorConstancy(object): 140 | """ color constancy operation """ 141 | def __init__(self, power=6, gamma=None): 142 | self.power = power 143 | self.gamma = gamma 144 | 145 | def __call__(self, img): 146 | img = color_constancy(np.array(img), self.power, self.gamma) 147 | return Image.fromarray(img.astype(np.uint8)) 148 | -------------------------------------------------------------------------------- /lib/dataset/__init__.py: -------------------------------------------------------------------------------- 1 | from .derm_7pt import derm_7pt 2 | from .isic import isic_2017, isic_2018, isic_2019 3 | -------------------------------------------------------------------------------- /lib/dataset/derm_7pt.py: -------------------------------------------------------------------------------- 1 | from .baseset import BaseSet 2 | import cv2 3 | import os 4 | 5 | 6 | class derm_7pt(BaseSet): 7 | def __init__(self, mode='train', cfg=None): 8 | super().__init__(mode, cfg) 9 | 10 | def _get_image(self, now_info): 11 | if self.data_type == "jpg": 12 | if self.cfg.TRAIN.SAMPLER.IMAGE_TYPE == "derm": 13 | fpath = os.path.join(self.data_root, now_info["derm_path"]) 14 | else: 15 | fpath = os.path.join(self.data_root, now_info["clinic_path"]) 16 | img = self.imread_with_retry(fpath) 17 | if self.color_space == "RGB": 18 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 19 | return img 20 | -------------------------------------------------------------------------------- /lib/dataset/isic.py: -------------------------------------------------------------------------------- 1 | from .baseset import BaseSet 2 | import cv2 3 | import os 4 | 5 | 6 | class ISIC(BaseSet): 7 | def __init__(self, mode='train', cfg=None): 8 | super().__init__(mode, cfg) 9 | 10 | def _get_image(self, now_info): 11 | if self.data_type == "jpg": 12 | fpath = os.path.join(self.data_root, now_info["derm_path"]) 13 | img = self.imread_with_retry(fpath) 14 | if self.color_space == "RGB": 15 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 16 | return img 17 | 18 | 19 | class isic_2017(ISIC): 20 | def __init__(self, mode='train', cfg=None): 21 | super().__init__(mode, cfg) 22 | self.dataset_name = "isic_2017" 23 | 24 | 25 | class isic_2018(ISIC): 26 | def __init__(self, mode='train', cfg=None): 27 | super().__init__(mode, cfg) 28 | self.dataset_name = "isic_2018" 29 | 30 | 31 | class isic_2019(ISIC): 32 | def __init__(self, mode='train', cfg=None): 33 | super().__init__(mode, cfg) 34 | self.dataset_name = "isic_2019" 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /lib/loss/__init__.py: -------------------------------------------------------------------------------- 1 | from .loss import CrossEntropy, LDAMLoss, FocalLoss, LOWLoss, GHMCLoss, CCELoss, MWNLoss 2 | -------------------------------------------------------------------------------- /lib/modules/__init__.py: -------------------------------------------------------------------------------- 1 | from .classifier_ops import * 2 | from .pooling_ops import GAP, Identity 3 | from .dropblock import DropBlock2D, DropBlock3D 4 | from .droplock_scheduler import DropLockScheduler -------------------------------------------------------------------------------- /lib/modules/classifier_ops.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | # for LDAM Loss 7 | class FCNorm(nn.Module): 8 | def __init__(self, num_features, num_classes): 9 | super(FCNorm, self).__init__() 10 | self.weight = nn.Parameter(torch.FloatTensor(num_classes, num_features)) 11 | self.weight.data.uniform_(-1, 1).renorm_(2, 1, 1e-5).mul_(1e5) 12 | 13 | def forward(self, x): 14 | out = F.linear(F.normalize(x), F.normalize(self.weight)) 15 | return out 16 | 17 | -------------------------------------------------------------------------------- /lib/modules/dropblock.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn.functional as F 3 | from torch import nn 4 | 5 | 6 | class DropBlock2D(nn.Module): 7 | r"""Randomly zeroes 2D spatial blocks of the input tensor. 8 | 9 | As described in the paper 10 | `DropBlock: A regularization method for convolutional networks`_ , 11 | dropping whole blocks of feature map allows to remove semantic 12 | information as compared to regular dropout. 13 | 14 | Args: 15 | drop_prob (float): probability of an element to be dropped. 16 | block_size (int): size of the block to drop 17 | 18 | Shape: 19 | - Input: `(N, C, H, W)` 20 | - Output: `(N, C, H, W)` 21 | 22 | .. _DropBlock: A regularization method for convolutional networks: 23 | https://arxiv.org/abs/1810.12890 24 | 25 | """ 26 | 27 | def __init__(self, drop_prob=0.1, block_size=5): 28 | super(DropBlock2D, self).__init__() 29 | 30 | self.drop_prob = drop_prob 31 | self.block_size = block_size 32 | 33 | def forward(self, x): 34 | # shape: (bsize, channels, height, width) 35 | 36 | assert x.dim() == 4, \ 37 | "Expected input with 4 dimensions (bsize, channels, height, width)" 38 | 39 | if not self.training or self.drop_prob == 0.: 40 | return x 41 | else: 42 | # get gamma value 43 | gamma = self._compute_gamma(x) 44 | 45 | # sample mask 46 | mask = (torch.rand(x.shape[0], *x.shape[2:]) < gamma).float() 47 | 48 | # place mask on input device 49 | mask = mask.to(x.device) 50 | 51 | # compute block mask 52 | block_mask = self._compute_block_mask(mask) 53 | 54 | # apply block mask 55 | out = x * block_mask[:, None, :, :] 56 | 57 | # scale output 58 | out = out * block_mask.numel() / block_mask.sum() 59 | 60 | return out 61 | 62 | def _compute_block_mask(self, mask): 63 | block_mask = F.max_pool2d(input=mask[:, None, :, :], 64 | kernel_size=(self.block_size, self.block_size), 65 | stride=(1, 1), 66 | padding=self.block_size // 2) 67 | 68 | if self.block_size % 2 == 0: 69 | block_mask = block_mask[:, :, :-1, :-1] 70 | 71 | block_mask = 1 - block_mask.squeeze(1) 72 | 73 | return block_mask 74 | 75 | def _compute_gamma(self, x): 76 | return self.drop_prob / (self.block_size ** 2) 77 | 78 | 79 | class DropBlock3D(DropBlock2D): 80 | r"""Randomly zeroes 3D spatial blocks of the input tensor. 81 | 82 | An extension to the concept described in the paper 83 | `DropBlock: A regularization method for convolutional networks`_ , 84 | dropping whole blocks of feature map allows to remove semantic 85 | information as compared to regular dropout. 86 | 87 | Args: 88 | drop_prob (float): probability of an element to be dropped. 89 | block_size (int): size of the block to drop 90 | 91 | Shape: 92 | - Input: `(N, C, D, H, W)` 93 | - Output: `(N, C, D, H, W)` 94 | 95 | .. _DropBlock: A regularization method for convolutional networks: 96 | https://arxiv.org/abs/1810.12890 97 | 98 | """ 99 | 100 | def __init__(self, drop_prob, block_size): 101 | super(DropBlock3D, self).__init__(drop_prob, block_size) 102 | 103 | def forward(self, x): 104 | # shape: (bsize, channels, depth, height, width) 105 | 106 | assert x.dim() == 5, \ 107 | "Expected input with 5 dimensions (bsize, channels, depth, height, width)" 108 | 109 | if not self.training or self.drop_prob == 0.: 110 | return x 111 | else: 112 | # get gamma value 113 | gamma = self._compute_gamma(x) 114 | 115 | # sample mask 116 | mask = (torch.rand(x.shape[0], *x.shape[2:]) < gamma).float() 117 | 118 | # place mask on input device 119 | mask = mask.to(x.device) 120 | 121 | # compute block mask 122 | block_mask = self._compute_block_mask(mask) 123 | 124 | # apply block mask 125 | out = x * block_mask[:, None, :, :, :] 126 | 127 | # scale output 128 | out = out * block_mask.numel() / block_mask.sum() 129 | 130 | return out 131 | 132 | def _compute_block_mask(self, mask): 133 | block_mask = F.max_pool3d(input=mask[:, None, :, :, :], 134 | kernel_size=(self.block_size, self.block_size, self.block_size), 135 | stride=(1, 1, 1), 136 | padding=self.block_size // 2) 137 | 138 | if self.block_size % 2 == 0: 139 | block_mask = block_mask[:, :, :-1, :-1, :-1] 140 | 141 | block_mask = 1 - block_mask.squeeze(1) 142 | 143 | return block_mask 144 | 145 | def _compute_gamma(self, x): 146 | return self.drop_prob / (self.block_size ** 3) 147 | -------------------------------------------------------------------------------- /lib/modules/droplock_scheduler.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from torch import nn 3 | 4 | 5 | class DropLockScheduler(nn.Module): 6 | def __init__(self, dropblock): 7 | super(DropLockScheduler, self).__init__() 8 | self.dropblock = dropblock 9 | self.i = 0 10 | self.drop_values = None 11 | 12 | def forward(self, x): 13 | return self.dropblock(x) 14 | 15 | def step(self): 16 | if self.i < len(self.drop_values): 17 | self.dropblock.drop_prob = self.drop_values[self.i] 18 | self.i += 1 19 | 20 | def init_para(self, start=0.0, stop=0.1, block_size=5, nr_steps=5000): 21 | self.i = 0 22 | self.drop_values = np.linspace(start=start, stop=stop, num=int(nr_steps)) 23 | self.dropblock.drop_prob = start 24 | self.dropblock.block_size = block_size 25 | -------------------------------------------------------------------------------- /lib/modules/pooling_ops.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | 4 | class GAP(nn.Module): 5 | """Global Average pooling 6 | Widely used in ResNet, Inception, DenseNet, etc. 7 | """ 8 | 9 | def __init__(self): 10 | super(GAP, self).__init__() 11 | self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) 12 | 13 | def forward(self, x): 14 | x = self.avgpool(x) 15 | return x 16 | 17 | 18 | class Identity(nn.Module): 19 | def __init__(self): 20 | super(Identity, self).__init__() 21 | 22 | def forward(self, x): 23 | return x 24 | 25 | -------------------------------------------------------------------------------- /lib/net/__init__.py: -------------------------------------------------------------------------------- 1 | from .network import Network 2 | -------------------------------------------------------------------------------- /lib/net/network.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from lib.modules import GAP, Identity, FCNorm 4 | import lib.backbone.all_models as all_models 5 | 6 | 7 | class Network(nn.Module): 8 | def __init__(self, cfg, mode="train", num_classes=1000): 9 | super(Network, self).__init__() 10 | pretrain = ( 11 | True if mode == "train" and cfg.RESUME_MODEL == "" and cfg.BACKBONE.PRETRAINED 12 | else False 13 | ) 14 | 15 | self.num_classes = num_classes 16 | self.cfg = cfg 17 | 18 | model = all_models.get_model(self.cfg.BACKBONE.TYPE, pretrain) 19 | # BBN method, please see the paper: "BBN: Bilateral-Branch Network with 20 | # Cumulative Learning for Long-Tailed Visual Recognition" 21 | if self.cfg.BACKBONE.BBN: 22 | self.model = all_models.get_bbn_model(self.cfg.BACKBONE.TYPE, model) 23 | self.bbn_backbone = self.model.bbn_backbone 24 | self.bbn_cb_block = self.model.bbn_cb_block 25 | self.bbn_rb_block = self.model.bbn_rb_block 26 | 27 | self.module = self._get_module() 28 | self.classifier = self._get_classifer() 29 | else: 30 | self.model, self.last_layer = all_models.modify_last_layer(self.cfg.BACKBONE.TYPE, model, self.num_classes, 31 | self.cfg) 32 | # if use drop block, set the parameter 33 | if 'DropBlock' in self.cfg.BACKBONE.TYPE: 34 | self.model.init_dropblock_para(start=0.0, stop=self.cfg.BACKBONE.DROP.BLOCK_PROB, 35 | block_size=self.cfg.BACKBONE.DROP.BLOCK_SIZE, 36 | nr_steps=self.cfg.BACKBONE.DROP.NR_STEPS) 37 | self.model.init_dropout_para(drop_prob=self.cfg.BACKBONE.DROP.OUT_PROB) 38 | 39 | def forward(self, x, **kwargs): 40 | if self.cfg.BACKBONE.BBN: # BBN model 41 | if "feature_cb" in kwargs: # used for train 42 | x = self.bbn_backbone(x) 43 | x = self.bbn_cb_block(x) 44 | x = self.module(x) 45 | x = x.view(x.shape[0], -1) 46 | elif "feature_rb" in kwargs: # used for train 47 | x = self.bbn_backbone(x) 48 | x = self.bbn_rb_block(x) 49 | x = self.module(x) 50 | x = x.view(x.shape[0], -1) 51 | elif "feature_flag" in kwargs: # used for valid 52 | x = self.bbn_backbone(x) 53 | out1 = self.bbn_cb_block(x) 54 | out2 = self.bbn_rb_block(x) 55 | out = torch.cat((out1, out2), dim=1) 56 | x = self.module(out) 57 | x = x.view(x.shape[0], -1) 58 | elif "classifier_flag" in kwargs: # used for train and valid 59 | x = self.classifier(x) 60 | if 'DropBlock' in self.cfg.BACKBONE.TYPE: # update drop block parameter 61 | self.model.dropblock_step() 62 | else: # Normal model 63 | x = self.model(x) 64 | if 'DropBlock' in self.cfg.BACKBONE.TYPE: # update drop block parameter 65 | self.model.dropblock_step() 66 | 67 | return x 68 | 69 | def freeze_backbone(self): 70 | print("Freezing backbone .......") 71 | if self.cfg.BACKBONE.BBN: 72 | for p in self.model.parameters(): 73 | p.requires_grad = False 74 | else: 75 | for p in self.model.parameters(): 76 | p.requires_grad = False 77 | # let the last classification layer parameter not freeze 78 | for p in self.last_layer.parameters(): 79 | p.requires_grad = True 80 | 81 | def unfreeze_backbone(self): 82 | print("Unfreezing backbone .......") 83 | for p in self.model.parameters(): 84 | p.requires_grad = True 85 | 86 | def get_feature_length(self): 87 | num_features = all_models.get_feature_length(self.cfg.BACKBONE.TYPE, self.model) 88 | if self.cfg.BACKBONE.BBN: 89 | num_features *= 2 90 | return num_features 91 | 92 | def _get_module(self): 93 | """only for BBN model""" 94 | module_type = self.cfg.MODULE.TYPE 95 | if module_type == "GAP": 96 | module = GAP() 97 | elif module_type == "Identity": 98 | module = Identity() 99 | else: 100 | raise NotImplementedError 101 | 102 | return module 103 | 104 | def _get_classifer(self): 105 | """only for BBN model""" 106 | bias_flag = self.cfg.CLASSIFIER.BIAS 107 | 108 | num_features = self.get_feature_length() 109 | if self.cfg.CLASSIFIER.TYPE == "FCNorm": 110 | classifier = FCNorm(num_features, self.num_classes) 111 | elif self.cfg.CLASSIFIER.TYPE == "FC": 112 | classifier = nn.Linear(num_features, self.num_classes, bias=bias_flag) 113 | else: 114 | raise NotImplementedError 115 | 116 | if 'DropBlock' in self.cfg.BACKBONE.TYPE: 117 | classifier = nn.Sequential( 118 | self.model.bbn_drop_out, 119 | classifier 120 | ) 121 | 122 | return classifier 123 | -------------------------------------------------------------------------------- /lib/utils/Nadam.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class Nadam(torch.optim.Optimizer): 5 | """Implements Nadam algorithm (a variant of Adam based on Nesterov momentum). 6 | 7 | It has been proposed in `Incorporating Nesterov Momentum into Adam`__. 8 | 9 | Arguments: 10 | params (iterable): iterable of parameters to optimize or dicts defining 11 | parameter groups 12 | lr (float, optional): learning rate (default: 2e-3) 13 | betas (Tuple[float, float], optional): coefficients used for computing 14 | running averages of gradient and its square 15 | eps (float, optional): term added to the denominator to improve 16 | numerical stability (default: 1e-8) 17 | weight_decay (float, optional): weight decay (L2 penalty) (default: 0) 18 | schedule_decay (float, optional): momentum schedule decay (default: 4e-3) 19 | 20 | __ http://cs229.stanford.edu/proj2015/054_report.pdf 21 | __ http://www.cs.toronto.edu/~fritz/absps/momentum.pdf 22 | """ 23 | 24 | def __init__(self, params, lr=2e-3, betas=(0.9, 0.999), eps=1e-8, 25 | weight_decay=0, schedule_decay=4e-3): 26 | defaults = dict(lr=lr, betas=betas, eps=eps, 27 | weight_decay=weight_decay, schedule_decay=schedule_decay) 28 | super(Nadam, self).__init__(params, defaults) 29 | 30 | def step(self, closure=None): 31 | """Performs a single optimization step. 32 | 33 | Arguments: 34 | closure (callable, optional): A closure that reevaluates the model 35 | and returns the loss. 36 | """ 37 | loss = None 38 | if closure is not None: 39 | loss = closure() 40 | 41 | for group in self.param_groups: 42 | for p in group['params']: 43 | if p.grad is None: 44 | continue 45 | grad = p.grad.data 46 | state = self.state[p] 47 | 48 | # State initialization 49 | if len(state) == 0: 50 | state['step'] = 0 51 | state['m_schedule'] = 1. 52 | state['exp_avg'] = grad.new().resize_as_(grad).zero_() 53 | state['exp_avg_sq'] = grad.new().resize_as_(grad).zero_() 54 | 55 | # Warming momentum schedule 56 | m_schedule = state['m_schedule'] 57 | schedule_decay = group['schedule_decay'] 58 | exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] 59 | beta1, beta2 = group['betas'] 60 | eps = group['eps'] 61 | 62 | state['step'] += 1 63 | 64 | if group['weight_decay'] != 0: 65 | grad = grad.add(group['weight_decay'], p.data) 66 | 67 | momentum_cache_t = beta1 * \ 68 | (1. - 0.5 * (0.96 ** (state['step'] * schedule_decay))) 69 | momentum_cache_t_1 = beta1 * \ 70 | (1. - 0.5 * 71 | (0.96 ** ((state['step'] + 1) * schedule_decay))) 72 | m_schedule_new = m_schedule * momentum_cache_t 73 | m_schedule_next = m_schedule * momentum_cache_t * momentum_cache_t_1 74 | state['m_schedule'] = m_schedule_new 75 | 76 | # Decay the first and second moment running average coefficient 77 | bias_correction2 = 1 - beta2 ** state['step'] 78 | 79 | exp_avg.mul_(beta1).add_(1 - beta1, grad) 80 | exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad) 81 | exp_avg_sq_prime = exp_avg_sq.div(1. - bias_correction2) 82 | 83 | denom = exp_avg_sq_prime.sqrt_().add_(group['eps']) 84 | 85 | p.data.addcdiv_(-group['lr'] * (1. - momentum_cache_t) / (1. - m_schedule_new), grad, denom) 86 | p.data.addcdiv_(-group['lr'] * momentum_cache_t_1 / (1. - m_schedule_next), exp_avg, denom) 87 | 88 | return loss 89 | -------------------------------------------------------------------------------- /lib/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /lib/utils/lr_scheduler.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from bisect import bisect_right 3 | 4 | 5 | class WarmupMultiStepLR(torch.optim.lr_scheduler._LRScheduler): 6 | def __init__( 7 | self, 8 | optimizer, 9 | milestones, 10 | gamma=0.1, 11 | warmup_factor=1.0 / 3, 12 | warmup_epochs=5, 13 | warmup_method="linear", 14 | last_epoch=-1, 15 | ): 16 | if not list(milestones) == sorted(milestones): 17 | raise ValueError( 18 | "Milestones should be a list of" " increasing integers. Got {}", 19 | milestones, 20 | ) 21 | 22 | if warmup_method not in ("constant", "linear"): 23 | raise ValueError( 24 | "Only 'constant' or 'linear' warmup_method accepted" 25 | "got {}".format(warmup_method) 26 | ) 27 | self.milestones = milestones 28 | self.gamma = gamma 29 | self.warmup_factor = warmup_factor 30 | self.warmup_epochs = warmup_epochs 31 | self.warmup_method = warmup_method 32 | super(WarmupMultiStepLR, self).__init__(optimizer, last_epoch) 33 | 34 | def get_lr(self): 35 | warmup_factor = 1 36 | if self.last_epoch < self.warmup_epochs: 37 | if self.warmup_method == "constant": 38 | warmup_factor = self.warmup_factor 39 | elif self.warmup_method == "linear": 40 | alpha = float(self.last_epoch) / self.warmup_epochs 41 | warmup_factor = self.warmup_factor * (1 - alpha) + alpha 42 | return [ 43 | base_lr 44 | * warmup_factor 45 | * self.gamma ** bisect_right(self.milestones, self.last_epoch) 46 | for base_lr in self.base_lrs 47 | ] 48 | 49 | -------------------------------------------------------------------------------- /lib/utils/utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | import os 4 | 5 | import torch 6 | from lib.utils.lr_scheduler import WarmupMultiStepLR 7 | from lib.net import Network 8 | from lib.utils.Nadam import Nadam 9 | 10 | 11 | def create_logger(cfg): 12 | log_dir = os.path.join(cfg.OUTPUT_DIR, cfg.NAME, "logs") 13 | if not os.path.exists(log_dir): 14 | os.makedirs(log_dir) 15 | time_str = time.strftime("%Y-%m-%d-%H-%M") 16 | log_name = "{}__{}.log".format(cfg.NAME, time_str) 17 | log_file = os.path.join(log_dir, log_name) 18 | # set up logger 19 | print("=> creating log {}".format(log_file)) 20 | head = "%(asctime)-15s %(message)s" 21 | logging.basicConfig(filename=str(log_file), format=head) 22 | logger = logging.getLogger() 23 | logger.setLevel(logging.INFO) 24 | console = logging.StreamHandler() 25 | logging.getLogger("").addHandler(console) 26 | 27 | logger.info("---------------------Cfg is set as follow--------------------") 28 | logger.info(cfg) 29 | logger.info("-------------------------------------------------------------") 30 | return logger, log_file 31 | 32 | 33 | def get_optimizer(cfg, model): 34 | base_lr = cfg.TRAIN.OPTIMIZER.BASE_LR * len(cfg.GPUS) 35 | params = [] 36 | 37 | for name, p in model.named_parameters(): 38 | params.append({"params": p}) 39 | 40 | if cfg.TRAIN.OPTIMIZER.TYPE == "SGD": 41 | optimizer = torch.optim.SGD( 42 | params, 43 | lr=base_lr, 44 | momentum=cfg.TRAIN.OPTIMIZER.MOMENTUM, 45 | weight_decay=cfg.TRAIN.OPTIMIZER.WEIGHT_DECAY, 46 | nesterov=True, 47 | ) 48 | elif cfg.TRAIN.OPTIMIZER.TYPE == "ADAM": 49 | optimizer = torch.optim.Adam( 50 | params, 51 | lr=base_lr, 52 | betas=(0.9, 0.999), 53 | weight_decay=cfg.TRAIN.OPTIMIZER.WEIGHT_DECAY, 54 | ) 55 | elif cfg.TRAIN.OPTIMIZER.TYPE == "NADAM": 56 | optimizer = Nadam( 57 | params, 58 | lr=base_lr, 59 | betas=(0.9, 0.999), 60 | weight_decay=cfg.TRAIN.OPTIMIZER.WEIGHT_DECAY, 61 | ) 62 | elif cfg.TRAIN.OPTIMIZER.TYPE == "RMSPROP": 63 | optimizer = torch.optim.RMSprop( 64 | params, 65 | lr=base_lr, 66 | alpha=0.9, 67 | weight_decay=cfg.TRAIN.OPTIMIZER.WEIGHT_DECAY, 68 | ) 69 | 70 | return optimizer 71 | 72 | 73 | def get_scheduler(cfg, optimizer): 74 | if cfg.TRAIN.LR_SCHEDULER.TYPE == "steplr": 75 | scheduler = torch.optim.lr_scheduler.StepLR( 76 | optimizer, 77 | step_size=cfg.TRAIN.LR_SCHEDULER.LR_LOWER_STEP, 78 | gamma=cfg.TRAIN.LR_SCHEDULER.LR_FACTOR, 79 | ) 80 | elif cfg.TRAIN.LR_SCHEDULER.TYPE == "multistep": 81 | scheduler = torch.optim.lr_scheduler.MultiStepLR( 82 | optimizer, 83 | cfg.TRAIN.LR_SCHEDULER.LR_STEP, 84 | gamma=cfg.TRAIN.LR_SCHEDULER.LR_FACTOR, 85 | ) 86 | elif cfg.TRAIN.LR_SCHEDULER.TYPE == "cosine": 87 | if cfg.TRAIN.LR_SCHEDULER.COSINE_DECAY_END > 0: 88 | scheduler = torch.optim.lr_scheduler.CosineAnnealingLR( 89 | optimizer, T_max=cfg.TRAIN.LR_SCHEDULER.COSINE_DECAY_END, eta_min=1e-4 90 | ) 91 | else: 92 | scheduler = torch.optim.lr_scheduler.CosineAnnealingLR( 93 | optimizer, T_max=cfg.TRAIN.MAX_EPOCH, eta_min=1e-4 94 | ) 95 | elif cfg.TRAIN.LR_SCHEDULER.TYPE == "warmup": 96 | scheduler = WarmupMultiStepLR( 97 | optimizer, 98 | cfg.TRAIN.LR_SCHEDULER.LR_STEP, 99 | gamma=cfg.TRAIN.LR_SCHEDULER.LR_FACTOR, 100 | warmup_epochs=cfg.TRAIN.LR_SCHEDULER.WARM_EPOCH, 101 | ) 102 | else: 103 | raise NotImplementedError("Unsupported LR Scheduler: {}".format(cfg.TRAIN.LR_SCHEDULER.TYPE)) 104 | 105 | return scheduler 106 | 107 | 108 | def get_model(cfg, num_classes, device, logger): 109 | model = Network(cfg, mode="train", num_classes=num_classes) 110 | 111 | if cfg.BACKBONE.FREEZE or cfg.BACKBONE.PRE_FREEZE: 112 | model.freeze_backbone() 113 | logger.info("Backbone has been freezed") 114 | 115 | if device == torch.device("cuda"): 116 | model = torch.nn.DataParallel(model).cuda() 117 | 118 | return model 119 | 120 | 121 | -------------------------------------------------------------------------------- /main/_init_paths.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | from os import path as osp 4 | 5 | def add_path(path): 6 | if path not in sys.path: 7 | sys.path.insert(0, path) 8 | try: 9 | os.environ["PYTHONPATH"] = path + ":" + os.environ["PYTHONPATH"] 10 | except KeyError: 11 | os.environ["PYTHONPATH"] = path 12 | 13 | 14 | this_dir = osp.dirname(__file__) 15 | 16 | # Add root fold to PYTHONPATH 17 | lib_path = osp.join(this_dir, '..') 18 | add_path(lib_path) 19 | # print(sys.path) 20 | -------------------------------------------------------------------------------- /main/jsons/readme.md: -------------------------------------------------------------------------------- 1 | * This folder stores the data files needed by dataLoader, which can be generated by programs such as convert_from_Derm_7pt.py in the tools directory. 2 | * As a demo, you can refer to converted_Derm_7pt_train.json 3 | -------------------------------------------------------------------------------- /main/train.py: -------------------------------------------------------------------------------- 1 | import _init_paths 2 | from lib.loss import * 3 | from lib.dataset import * 4 | from lib.config import cfg, update_config, update_cfg_name 5 | from lib.utils.utils import ( 6 | create_logger, 7 | get_optimizer, 8 | get_scheduler, 9 | get_model, 10 | ) 11 | from lib.core.function import train_model, valid_model 12 | from lib.core.combiner import Combiner 13 | 14 | import numpy as np 15 | import torch 16 | import os, shutil 17 | from torch.utils.data import DataLoader 18 | import argparse 19 | import warnings 20 | import click 21 | from tensorboardX import SummaryWriter 22 | import torch.backends.cudnn as cudnn 23 | import ast 24 | import csv 25 | 26 | 27 | def parse_args(): 28 | ''' 29 | example: python train.py 30 | --cfg ../configs/isic_2018.yaml 31 | NAME "_1" LOSS.LOSS_TYPE "FocalLoss" 32 | :return: 33 | ''' 34 | parser = argparse.ArgumentParser(description="codes for MBIT") 35 | 36 | parser.add_argument( 37 | "--cfg", 38 | help="decide which cfg to use", 39 | required=False, 40 | default="../configs/isic_2017.yaml", 41 | type=str, 42 | ) 43 | parser.add_argument( 44 | "--ar", 45 | help="decide whether to use auto resume", 46 | type=ast.literal_eval, 47 | dest='auto_resume', 48 | required=False, 49 | default=True, 50 | ) 51 | 52 | parser.add_argument( 53 | "opts", 54 | help="modify config options using the command-line", 55 | default=None, 56 | nargs=argparse.REMAINDER, 57 | ) 58 | 59 | args = parser.parse_args() 60 | return args 61 | 62 | 63 | if __name__ == "__main__": 64 | args = parse_args() 65 | update_config(cfg, args) 66 | update_cfg_name(cfg) # modify the cfg.NAME 67 | logger, log_file = create_logger(cfg) 68 | warnings.filterwarnings("ignore") 69 | cudnn.benchmark = True 70 | auto_resume = args.auto_resume 71 | strGPUs = [str(x) for x in cfg.GPUS] 72 | os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(strGPUs) # specify which GPUs to use 73 | 74 | train_set = eval(cfg.DATASET.DATASET)("train", cfg) 75 | valid_set = eval(cfg.DATASET.DATASET)("valid", cfg) 76 | 77 | num_classes = train_set.get_num_classes() 78 | device = torch.device("cpu" if cfg.CPU_MODE else "cuda") 79 | 80 | num_class_list = train_set.get_num_class_list() 81 | 82 | para_dict = { 83 | "num_classes": num_classes, 84 | "num_class_list": num_class_list, 85 | "cfg": cfg, 86 | "device": device, 87 | } 88 | 89 | # ----- begin model builder ----- 90 | max_epoch = cfg.TRAIN.MAX_EPOCH 91 | loss_fuc = eval(cfg.LOSS.LOSS_TYPE)(para_dict=para_dict) 92 | model = get_model(cfg, num_classes, device, logger) 93 | combiner = Combiner(cfg, device, model, loss_fuc) 94 | optimizer = get_optimizer(cfg, model) 95 | scheduler = get_scheduler(cfg, optimizer) 96 | # ----- end model builder ----- 97 | 98 | trainLoader = DataLoader( 99 | train_set, 100 | batch_size=cfg.TRAIN.BATCH_SIZE * len(cfg.GPUS), 101 | shuffle=cfg.TRAIN.SHUFFLE, 102 | num_workers=cfg.TRAIN.NUM_WORKERS, 103 | pin_memory=cfg.PIN_MEMORY, 104 | drop_last=True 105 | ) 106 | 107 | test_batch_size = cfg.TEST.BATCH_SIZE * len(cfg.GPUS) 108 | val_sample_repeat_num = 0 109 | if cfg.TRAIN.SAMPLER.MULTI_CROP.ENABLE: 110 | val_sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_CROP.CROP_NUM 111 | if cfg.TRAIN.SAMPLER.MULTI_SCALE.ENABLE: 112 | val_sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_SCALE.SCALE_NUM 113 | if val_sample_repeat_num > 0: 114 | test_batch_size = int(test_batch_size / val_sample_repeat_num) * val_sample_repeat_num 115 | validLoader = DataLoader( 116 | valid_set, 117 | batch_size=test_batch_size, 118 | shuffle=False, 119 | num_workers=cfg.TEST.NUM_WORKERS, 120 | pin_memory=cfg.PIN_MEMORY, 121 | ) 122 | 123 | model_dir = os.path.join(cfg.OUTPUT_DIR, cfg.NAME, "models") 124 | code_dir = os.path.join(cfg.OUTPUT_DIR, cfg.NAME, "codes") 125 | tensorboard_dir = ( 126 | os.path.join(cfg.OUTPUT_DIR, cfg.NAME, "tensorboard") 127 | if cfg.TRAIN.TENSORBOARD.ENABLE 128 | else None 129 | ) 130 | 131 | if not os.path.exists(model_dir): 132 | os.makedirs(model_dir) 133 | else: 134 | logger.info( 135 | "This directory has already existed, Please remember to modify your cfg.NAME" 136 | ) 137 | if not click.confirm( 138 | "\033[1;31;40mContinue and override the former directory?\033[0m", 139 | default=False, 140 | ): 141 | exit(0) 142 | shutil.rmtree(code_dir) 143 | if tensorboard_dir is not None and os.path.exists(tensorboard_dir): 144 | shutil.rmtree(tensorboard_dir) 145 | print("=> output model will be saved in {}".format(model_dir)) 146 | this_dir = os.path.dirname(__file__) 147 | ignore = shutil.ignore_patterns( 148 | "*.pyc", "*.so", "*.out", "*pycache*", "*.pth", ".pyth", "*build*", "*output*", "*datasets*", 149 | "pretrained_models" 150 | ) 151 | shutil.copytree(os.path.join(this_dir, ".."), code_dir, ignore=ignore) 152 | 153 | if tensorboard_dir is not None: 154 | dummy_input = torch.rand((1, 3) + cfg.INPUT_SIZE).to(device) 155 | writer = SummaryWriter(log_dir=tensorboard_dir) 156 | writer.add_graph(model if cfg.CPU_MODE else model.module, (dummy_input,)) 157 | else: 158 | writer = None 159 | 160 | best_result, best_epoch, start_epoch = 0, 0, 1 161 | best_metrics = {} 162 | 163 | # ----- begin resume --------- 164 | all_models = os.listdir(model_dir) 165 | if len(all_models) <= 1 or auto_resume is False: 166 | auto_resume = False 167 | else: 168 | all_models.remove("best_model.pth") 169 | resume_epoch = max([int(name.split(".")[0].split("_")[-1]) for name in all_models]) 170 | resume_model_path = os.path.join(model_dir, "epoch_{}.pth".format(resume_epoch)) 171 | 172 | if cfg.RESUME_MODEL != "" or auto_resume: 173 | if cfg.RESUME_MODEL == "": 174 | resume_model = resume_model_path 175 | else: 176 | resume_model = cfg.RESUME_MODEL if '/' in cfg.RESUME_MODEL else os.path.join(model_dir, cfg.RESUME_MODEL) 177 | logger.info("Loading checkpoint from {}...".format(resume_model)) 178 | checkpoint = torch.load( 179 | resume_model, map_location="cpu" if cfg.CPU_MODE else "cuda" 180 | ) 181 | 182 | model.load_state_dict(checkpoint['state_dict']) 183 | if cfg.RESUME_MODE != "state_dict": 184 | optimizer.load_state_dict(checkpoint['optimizer']) 185 | scheduler.load_state_dict(checkpoint['scheduler']) 186 | start_epoch = checkpoint['epoch'] + 1 187 | best_result = checkpoint['best_result'] 188 | best_epoch = checkpoint['best_epoch'] 189 | best_metrics = checkpoint['best_metrics'] 190 | # ----- end resume --------- 191 | 192 | logger.info("---------- Train start : model: {}, loss: {}, need augment: {} ----------".format( 193 | cfg.BACKBONE.TYPE + ("_BBN" if cfg.BACKBONE.BBN else ""), 194 | cfg.LOSS.LOSS_TYPE, 195 | str(cfg.TRAIN.SAMPLER.AUGMENT.NEED_AUGMENT)) 196 | ) 197 | 198 | for epoch in range(start_epoch, max_epoch + 1): 199 | scheduler.step() 200 | train_acc, train_loss = train_model( 201 | trainLoader, epoch, max_epoch, optimizer, 202 | combiner, cfg, logger, writer=writer 203 | ) 204 | 205 | loss_dict, acc_dict = {"train_loss": train_loss}, {"train_acc": train_acc} 206 | if cfg.VALID_STEP != -1 and epoch % cfg.VALID_STEP == 0: 207 | val_metrics = valid_model( 208 | validLoader, epoch, combiner, cfg, 209 | logger, writer=writer 210 | ) 211 | loss_dict["valid_loss"], acc_dict["valid_acc"] = val_metrics["loss"], val_metrics["acc"] 212 | 213 | compare_result = val_metrics["bacc"] # for all dataset, take the BACC as the key metric 214 | if compare_result > best_result: 215 | best_result, best_epoch = compare_result, epoch 216 | best_metrics = val_metrics 217 | torch.save( 218 | {'state_dict': model.state_dict(), 219 | 'epoch': epoch, 220 | 'best_result': best_result, 221 | 'best_epoch': best_epoch, 222 | 'best_metrics': best_metrics, 223 | 'scheduler': scheduler.state_dict(), 224 | 'optimizer': optimizer.state_dict(), 225 | }, os.path.join(model_dir, "best_model.pth") 226 | ) 227 | logger.info( 228 | "-------------- Best_Epoch:{:>3d} Best_result:{:>6.3f}% -------------- \n".format( 229 | best_epoch, best_result * 100 230 | ) 231 | ) 232 | 233 | model_save_path = os.path.join(model_dir, "epoch_{}.pth".format(epoch)) 234 | if epoch % cfg.SAVE_STEP == 0: 235 | torch.save({ 236 | 'state_dict': model.state_dict(), 237 | 'epoch': epoch, 238 | 'best_result': best_result, 239 | 'best_epoch': best_epoch, 240 | 'best_metrics': best_metrics, 241 | 'scheduler': scheduler.state_dict(), 242 | 'optimizer': optimizer.state_dict() 243 | }, model_save_path) 244 | 245 | if cfg.TRAIN.TENSORBOARD.ENABLE: 246 | writer.add_scalars("scalar/acc", acc_dict, epoch) 247 | writer.add_scalars("scalar/loss", loss_dict, epoch) 248 | if cfg.TRAIN.TENSORBOARD.ENABLE: 249 | writer.close() 250 | logger.info( 251 | "------------------- Train Finished :{} -------------------\n\n".format(cfg.NAME) 252 | ) 253 | 254 | if cfg.DATASET.DATASET == "isic_2017": 255 | auc_mean = (best_metrics["roc_auc"][0] + best_metrics["roc_auc"][1]) / 2.0 256 | spec_mean = np.mean(best_metrics["specificity"]) 257 | else: 258 | auc_mean = np.mean(best_metrics["roc_auc"]) 259 | spec_mean = np.mean(best_metrics["specificity"]) 260 | 261 | logger.info("------- Best Valid: Epoch: {:>3d} Valid_Loss: {:>6.4f} Valid_Acc: {:>6.3f}% -------".format( 262 | best_epoch, best_metrics["loss"], best_metrics["acc"] * 100) 263 | ) 264 | logger.info(" roc_auc.mean: {:>6.3f} f1_score: {:>6.4f} Balance_Acc: {:>6.3f}% ".format( 265 | auc_mean, best_metrics["f1_score"], best_metrics["bacc"] * 100) 266 | ) 267 | logger.info(" roc_auc: {} ".format(best_metrics["roc_auc"])) 268 | logger.info(" sensitivity: {} ".format(best_metrics["sensitivity"])) 269 | logger.info(" specificity: {} mean: {} ".format(best_metrics["specificity"], spec_mean)) 270 | logger.info(" fusion_matrix: \n{}\n ".format(best_metrics["fusion_matrix"])) 271 | 272 | 273 | -------------------------------------------------------------------------------- /main/valid.py: -------------------------------------------------------------------------------- 1 | import _init_paths 2 | from lib.net import Network 3 | from lib.config import cfg, update_config, update_cfg_name 4 | from lib.dataset import * 5 | import numpy as np 6 | import torch 7 | import os 8 | from torch.utils.data import DataLoader 9 | from tqdm import tqdm 10 | import argparse 11 | from lib.core.evaluate import FusionMatrix 12 | import torch.backends.cudnn as cudnn 13 | from lib.core.function import get_val_result, get_test_result, get_roc_auc 14 | import ast 15 | import csv 16 | 17 | 18 | def parse_args(): 19 | ''' 20 | example: python valid.py 21 | --cfg ../configs/isic_2018.yaml 22 | --test False 23 | :return: 24 | ''' 25 | parser = argparse.ArgumentParser(description="codes for MBIT") 26 | 27 | parser.add_argument( 28 | "--cfg", 29 | help="decide which cfg to use", 30 | required=True, 31 | default="", 32 | type=str, 33 | ) 34 | parser.add_argument( 35 | "--test", 36 | help="decide whether to be test or valid", 37 | required=False, 38 | default=False, 39 | type=ast.literal_eval, 40 | ) 41 | parser.add_argument( 42 | "opts", 43 | help="Modify config options using the command-line", 44 | default=None, 45 | nargs=argparse.REMAINDER, 46 | ) 47 | 48 | args = parser.parse_args() 49 | return args 50 | 51 | 52 | def test_model(data_loader, model, cfg, device): 53 | model.eval() 54 | num_classes = data_loader.dataset.get_num_classes() 55 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 56 | func = torch.nn.Sigmoid() 57 | num_classes -= 1 58 | func_1 = torch.nn.Softmax(dim=0) 59 | else: 60 | func = torch.nn.Softmax(dim=1) 61 | if cfg.DATASET.DATASET == "isic_2019": 62 | num_classes -= 1 # For isic_2019, the number of classes in the training set is 8, and there is also a class "unk" in the test set 63 | 64 | all_preds = np.zeros([data_loader.dataset.get_num_images(), num_classes]) 65 | ii = 0 66 | print("\n------- Start testing -------") 67 | print(" Test json file: {} \n".format(cfg.DATASET.TEST_JSON)) 68 | pbar = tqdm(total=len(data_loader)) 69 | with torch.no_grad(): 70 | for i, (image, label, meta) in enumerate(data_loader): 71 | image = image.to(device) 72 | if cfg.BACKBONE.BBN: # BBN model 73 | feature = model(image, feature_flag=True) 74 | output = model(feature, classifier_flag=True) 75 | else: 76 | output = model(image) 77 | now_pred = func(output) 78 | new_pred = get_test_result(now_pred.cpu().numpy(), cfg, num_classes) 79 | all_preds[ii:ii + new_pred.shape[0], :] = new_pred 80 | ii += new_pred.shape[0] 81 | pbar.update(1) 82 | 83 | pbar.close() 84 | 85 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 86 | all_unk = 1.0 - np.amax(all_preds, axis=1) 87 | all_preds = np.c_[all_preds, all_unk] 88 | elif cfg.DATASET.DATASET == "isic_2019": 89 | all_unk = np.zeros(all_preds.shape[0]) # For isic_2019, the results of the last class are all 0 90 | all_preds = np.c_[all_preds, all_unk] 91 | 92 | image_id_list = data_loader.dataset.get_image_id_list() 93 | 94 | # save the predictions to csv file 95 | model_dir = os.path.join(cfg.OUTPUT_DIR, cfg.NAME, "models") 96 | model_file = cfg.TEST.MODEL_FILE 97 | model_file = model_file.split('\\')[-1].split('.')[0] 98 | csv_file = "pridiction_" + str(model_file) + '.csv' 99 | csv_file = os.path.join(model_dir, csv_file) 100 | csv_fp = open(csv_file, 'w') 101 | csv_writer = csv.writer(csv_fp) 102 | table_head = ['image'] + cfg.DATASET.CLASS_NAME 103 | if cfg.DATASET.VALID_ADD_ONE_CLASS or cfg.DATASET.DATASET == "isic_2019": 104 | table_head = table_head + [cfg.DATASET.ADD_CLASS_NAME] 105 | # elif cfg.DATASET.DATASET == "isic_2017": 106 | # csv_writer.writerow(['image', 'MEL', 'SK', 'NV']) 107 | # elif cfg.DATASET.DATASET == "isic_2018": 108 | # csv_writer.writerow(['image', 'MEL', 'NV', 'BCC', 'AKIEC', 'BKL', 'DF', 'VASC']) 109 | # elif cfg.DATASET.DATASET == "isic_2019": 110 | # csv_writer.writerow(['image', 'MEL', 'NV', 'BCC', 'AK', 'BKL', 'DF', 'VASC', 'SCC', 'UNK']) 111 | csv_writer.writerow(table_head) 112 | for i in range(len(image_id_list)): 113 | # change predictions to binary value([0, 1]) 114 | pred = all_preds[i] 115 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 116 | pred = torch.from_numpy(pred) 117 | pred = func_1(pred).numpy() 118 | pred = pred.tolist() 119 | # for every row, change the max prediction to 0.51 if the max prediction is lower than 0.5 120 | row_new = pred 121 | if max(pred) <= 0.5: 122 | row_new[pred.index(max(pred))] = 0.51 123 | row_new = [image_id_list[i]] + row_new 124 | csv_writer.writerow(row_new) 125 | 126 | # close the csv file 127 | csv_fp.close() 128 | 129 | 130 | def valid_model(data_loader, model, cfg, device): 131 | model.eval() 132 | num_classes = data_loader.dataset.get_num_classes() 133 | fusion_matrix = FusionMatrix(num_classes) 134 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 135 | func = torch.nn.Sigmoid() 136 | num_classes -= 1 137 | else: 138 | func = torch.nn.Softmax(dim=1) 139 | 140 | all_preds = np.zeros([data_loader.dataset.get_num_images(), num_classes]) 141 | all_labels = np.zeros(data_loader.dataset.get_num_images()) 142 | ii = 0 143 | print("\n------- Start validation -------") 144 | print(" Valid json file: {} \n".format(cfg.DATASET.VALID_JSON)) 145 | pbar = tqdm(total=len(data_loader)) 146 | with torch.no_grad(): 147 | for i, (image, label, meta) in enumerate(data_loader): 148 | image, label = image.to(device), label.to(device) 149 | if cfg.BACKBONE.BBN: # BBN model 150 | feature = model(image, feature_flag=True) 151 | output = model(feature, classifier_flag=True) 152 | else: 153 | output = model(image) 154 | now_pred = func(output) 155 | new_pred, new_label = get_val_result(now_pred.cpu().numpy(), label.cpu().numpy(), cfg, num_classes) 156 | 157 | all_preds[ii:ii + new_pred.shape[0], :] = new_pred 158 | all_labels[ii:ii + new_pred.shape[0]] = new_label 159 | ii += new_pred.shape[0] 160 | pbar.update(1) 161 | 162 | pbar.close() 163 | 164 | if cfg.DATASET.VALID_ADD_ONE_CLASS: 165 | all_max = 1.0 - np.amax(all_preds, axis=1) 166 | all_preds = np.c_[all_preds, all_max] 167 | 168 | all_result = np.argmax(all_preds, 1) 169 | fusion_matrix.update(all_result, all_labels) 170 | roc_auc = get_roc_auc(all_preds, all_labels) 171 | 172 | metrics = {} 173 | metrics["sensitivity"] = fusion_matrix.get_rec_per_class() 174 | metrics["specificity"] = fusion_matrix.get_pre_per_class() 175 | metrics["f1_score"] = fusion_matrix.get_f1_score() 176 | metrics["roc_auc"] = roc_auc 177 | metrics["fusion_matrix"] = fusion_matrix.matrix 178 | if cfg.DATASET.DATASET == "isic_2017": 179 | acc_1 = fusion_matrix.get_binary_accuracy(0) 180 | acc_2 = fusion_matrix.get_binary_accuracy(1) 181 | metrics["acc"] = (acc_1 + acc_2) / 2.0 182 | metrics["bacc"] = (metrics["sensitivity"][0] + metrics["sensitivity"][1]) / 2.0 183 | auc_mean = (metrics["roc_auc"][0] + metrics["roc_auc"][1]) / 2.0 184 | spec_mean = (metrics["specificity"][0] + metrics["specificity"][1]) / 2.0 185 | else: 186 | metrics["acc"] = fusion_matrix.get_accuracy() 187 | metrics["bacc"] = fusion_matrix.get_balance_accuracy() 188 | auc_mean = np.mean(metrics["roc_auc"]) 189 | spec_mean = np.mean(metrics["specificity"]) 190 | 191 | print("\n------- Valid result: Valid_Acc: {:>6.3f}% Balance_Acc: {:>6.3f}% -------".format( 192 | metrics["acc"] * 100, metrics["bacc"] * 100) 193 | ) 194 | print(" roc_auc.mean: {:>6.3f} f1_score: {:>6.4f} ".format( 195 | auc_mean, metrics["f1_score"]) 196 | ) 197 | print(" roc_auc: {} ".format(metrics["roc_auc"])) 198 | print(" sensitivity: {} ".format(metrics["sensitivity"])) 199 | print(" specificity: {} mean: {} ".format(metrics["specificity"], spec_mean)) 200 | print(" fusion_matrix: \n{} ".format(metrics["fusion_matrix"])) 201 | 202 | 203 | if __name__ == "__main__": 204 | args = parse_args() 205 | update_config(cfg, args) 206 | update_cfg_name(cfg) # modify the cfg.NAME 207 | 208 | cudnn.benchmark = True 209 | strGPUs = [str(x) for x in cfg.GPUS] 210 | os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(strGPUs) # specify which GPUs to use 211 | 212 | if args.test: 213 | valid_test_set = eval(cfg.DATASET.DATASET)("test", cfg) 214 | else: 215 | valid_test_set = eval(cfg.DATASET.DATASET)("valid", cfg) 216 | num_classes = valid_test_set.get_num_classes() 217 | if cfg.DATASET.VALID_ADD_ONE_CLASS or (cfg.DATASET.DATASET == "isic_2019" and args.test): 218 | num_classes -= 1 # for isic_2019, the number of classes in the training set is 8, and there is also a class "unk" in the test set 219 | 220 | device = torch.device("cpu" if cfg.CPU_MODE else "cuda") 221 | model = Network(cfg, mode="val", num_classes=num_classes) 222 | 223 | if cfg.CPU_MODE: 224 | model = model.to(device) 225 | else: 226 | model = torch.nn.DataParallel(model).cuda() 227 | 228 | model_dir = os.path.join(cfg.OUTPUT_DIR, cfg.NAME, "models") 229 | model_file = cfg.TEST.MODEL_FILE 230 | if "/" in model_file: 231 | model_path = model_file 232 | else: 233 | model_path = os.path.join(model_dir, model_file) 234 | print("have loaded the best model from {}".format(model_path)) 235 | 236 | checkpoint = torch.load( 237 | model_path, map_location="cpu" if cfg.CPU_MODE else "cuda" 238 | ) 239 | model.load_state_dict(checkpoint['state_dict']) 240 | 241 | test_batch_size = cfg.TEST.BATCH_SIZE * len(cfg.GPUS) 242 | sample_repeat_num = 0 243 | if cfg.TRAIN.SAMPLER.MULTI_CROP.ENABLE: 244 | sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_CROP.CROP_NUM 245 | if cfg.TRAIN.SAMPLER.MULTI_SCALE.ENABLE: 246 | sample_repeat_num += cfg.TRAIN.SAMPLER.MULTI_SCALE.SCALE_NUM 247 | if sample_repeat_num > 0: 248 | test_batch_size = int(test_batch_size / sample_repeat_num) * sample_repeat_num 249 | val_test_loader = DataLoader( 250 | valid_test_set, 251 | batch_size=test_batch_size, 252 | shuffle=False, 253 | num_workers=cfg.TEST.NUM_WORKERS, 254 | pin_memory=cfg.PIN_MEMORY, 255 | ) 256 | 257 | if args.test: 258 | test_model(val_test_loader, model, cfg, device) 259 | else: 260 | valid_model(val_test_loader, model, cfg, device) 261 | 262 | 263 | -------------------------------------------------------------------------------- /pretrained_models/readme.md: -------------------------------------------------------------------------------- 1 | * This folder stores the pre-trained models of RegNet, which can be downloaded from the following URL: https://pan.baidu.com/s/10wGyDmvx1zBDxo-MAjjWsQ. Extraction code: 8888 -------------------------------------------------------------------------------- /tools/convert_from_Derm_7pt.py: -------------------------------------------------------------------------------- 1 | import json, os 2 | import argparse 3 | from tqdm import tqdm 4 | from PIL import Image 5 | 6 | 7 | def parse_args(): 8 | ''' 9 | example: python convert_from_Derm_7pt.py 10 | --file ./dataset_files/Derm_7pt_train.json 11 | --root /work/image/skin_cancer/derm_7_point/images/ 12 | --sp ../main/jsons/ 13 | ''' 14 | parser = argparse.ArgumentParser(description="Get the json file for Derm_7pt dataset.") 15 | 16 | parser.add_argument( 17 | "--file", 18 | help="origin json file to be converted", 19 | required=True, 20 | type=str, 21 | ) 22 | parser.add_argument( 23 | "--root", 24 | help="root path to the images", 25 | type=str, 26 | required=True, 27 | ) 28 | parser.add_argument( 29 | "--sp", 30 | help="save path for converted file ", 31 | type=str, 32 | required=False, 33 | default="." 34 | ) 35 | 36 | args = parser.parse_args() 37 | return args 38 | 39 | 40 | def convert(json_file, image_root): 41 | all_annos = json.load(open(json_file, 'r')) 42 | 43 | new_annos = [] 44 | print("Converting file {} ...".format(json_file)) 45 | max_class = 0 46 | for anno in tqdm(all_annos): 47 | clinic_path = os.path.join(image_root, anno["clinic_path"]) 48 | assert os.path.exists(clinic_path), \ 49 | 'Image file does not exist: {}'.format(clinic_path) 50 | sizes = Image.open(clinic_path).size 51 | clinic_width = sizes[0] 52 | clinic_height = sizes[1] 53 | 54 | derm_path = os.path.join(image_root, anno["derm_path"]) 55 | assert os.path.exists(derm_path), \ 56 | 'Image file does not exist: {}'.format(derm_path) 57 | sizes = Image.open(derm_path).size 58 | derm_width = sizes[0] 59 | derm_height = sizes[1] 60 | if max_class < anno["category_id"]: 61 | max_class = anno["category_id"] 62 | new_annos.append({"image_id": anno["image_id"], 63 | "category_id": anno["category_id"], 64 | "clinic_height": clinic_height, 65 | "clinic_width": clinic_width, 66 | "clinic_path": clinic_path, 67 | "derm_height": derm_height, 68 | "derm_width": derm_width, 69 | "derm_path": derm_path}) 70 | num_classes = max_class + 1 71 | return {"annotations": new_annos, 72 | "num_classes": num_classes} 73 | 74 | 75 | if __name__ == "__main__": 76 | args = parse_args() 77 | converted_annos = convert(args.file, args.root) 78 | save_path = os.path.join(args.sp, "converted_" + os.path.split(args.file)[-1]) 79 | print("Converted, Saveing converted file to {}".format(save_path)) 80 | with open(save_path, "w") as f: 81 | json.dump(converted_annos, f) 82 | 83 | 84 | -------------------------------------------------------------------------------- /tools/convert_from_ISIC_2017.py: -------------------------------------------------------------------------------- 1 | import json, os 2 | import argparse 3 | from tqdm import tqdm 4 | from PIL import Image 5 | import pandas as pd 6 | import ast 7 | import torchvision.transforms as transforms 8 | 9 | 10 | def parse_args(): 11 | ''' 12 | example: python convert_from_Derm_7pt.py 13 | --file ./dataset_files/ISIC_2017_Train.csv 14 | --root /SDG/work_image/image/skin_cancer/ISIC2017/ISIC-2017_Training_Data/ 15 | --sp ../main/jsons/ 16 | --small True 17 | --small_path ./dataset_image/isic_2017/train/ 18 | ''' 19 | parser = argparse.ArgumentParser(description="Get the json file for ISIC 2017 dataset.") 20 | 21 | parser.add_argument( 22 | "--file", 23 | help="origin csv file to be converted", 24 | required=True, 25 | type=str, 26 | ) 27 | parser.add_argument( 28 | "--root", 29 | help="root path to the images", 30 | type=str, 31 | required=True, 32 | ) 33 | parser.add_argument( 34 | "--sp", 35 | help="save path for converted file", 36 | type=str, 37 | required=False, 38 | default="." 39 | ) 40 | # Many images in isic 2017 are too big, which causes the dataloader to process images very slowly. 41 | # So we can reduce the images to a fixed size in advance. 42 | parser.add_argument( 43 | "--small", 44 | help="reduce the images to small", 45 | type=ast.literal_eval, 46 | required=False, 47 | default=False 48 | ) 49 | parser.add_argument( 50 | "--small_path", 51 | help="save path for small images", 52 | type=str, 53 | required=False, 54 | default="." 55 | ) 56 | 57 | args = parser.parse_args() 58 | return args 59 | 60 | 61 | def convert(args): 62 | csv_data = pd.read_csv(args.file) 63 | 64 | new_annos = [] 65 | print("Converting file {} ...".format(args.file)) 66 | 67 | for i in tqdm(range(len(csv_data))): 68 | image_id = csv_data.iloc[i]['image_id'] 69 | label = int(csv_data.iloc[i]["melanoma"]) \ 70 | + int(csv_data.iloc[i]["seborrheic_keratosis"]) * 2 \ 71 | + int(csv_data.iloc[i]["nv"]) * 3 - 1 72 | derm_path = os.path.join(args.root, image_id + ".jpg") 73 | assert os.path.exists(derm_path), \ 74 | 'Image file does not exist: {}'.format(derm_path) 75 | img = Image.open(derm_path) 76 | 77 | if args.small: 78 | resizing = transforms.Resize(450) 79 | img = resizing(img) 80 | # img.show() 81 | derm_path = os.path.join(args.small_path, image_id + ".jpg") 82 | img.save(derm_path, quality=95) 83 | 84 | sizes = img.size 85 | derm_width = sizes[0] 86 | derm_height = sizes[1] 87 | 88 | new_annos.append({"image_id": image_id, 89 | "category_id": label, 90 | "derm_height": derm_height, 91 | "derm_width": derm_width, 92 | "derm_path": derm_path}) 93 | num_classes = 3 94 | return {"annotations": new_annos, 95 | "num_classes": num_classes} 96 | 97 | 98 | if __name__ == "__main__": 99 | args = parse_args() 100 | converted_annos = convert(args) 101 | if args.small: 102 | save_path = os.path.join(args.sp, "converted_" + os.path.splitext(os.path.split(args.file)[-1])[0] + "_Small.json") 103 | else: 104 | save_path = os.path.join(args.sp, "converted_" + os.path.splitext(os.path.split(args.file)[-1])[0] + ".json") 105 | print("Converted, Saveing converted file to {}".format(save_path)) 106 | with open(save_path, "w") as f: 107 | json.dump(converted_annos, f) 108 | 109 | -------------------------------------------------------------------------------- /tools/convert_from_ISIC_2018.py: -------------------------------------------------------------------------------- 1 | import json, os 2 | import argparse 3 | from tqdm import tqdm 4 | from PIL import Image 5 | import pandas as pd 6 | import pickle 7 | 8 | 9 | def parse_args(): 10 | ''' 11 | example: python convert_from_ISIC_2018.py 12 | --csv_file ./dataset_files/ISIC_2018_Train.csv 13 | --pkl_file ./dataset_files/ISIC_2018_5foldcv_indices.pkl 14 | --root /work/image/skin_cancer/HAM10000/training_set/HAM10000_images/ 15 | --sp ../main/jsons/ 16 | ''' 17 | parser = argparse.ArgumentParser(description="Get the json file for ISIC 2018 dataset.") 18 | 19 | parser.add_argument( 20 | "--csv_file", 21 | help="origin csv file to be converted", 22 | required=True, 23 | type=str, 24 | ) 25 | parser.add_argument( 26 | "--pkl_file", 27 | help="pkl file to get the training and val index for cross validation", 28 | required=False, 29 | type=str, 30 | ) 31 | parser.add_argument( 32 | "--root", 33 | help="root path to the images", 34 | type=str, 35 | required=True, 36 | ) 37 | parser.add_argument( 38 | "--sp", 39 | help="save path for converted file ", 40 | type=str, 41 | required=False, 42 | default="." 43 | ) 44 | 45 | args = parser.parse_args() 46 | return args 47 | 48 | 49 | def convert(args): 50 | csv_data = pd.read_csv(args.csv_file) 51 | num_classes = 7 52 | class_dict = {'mel': 0, 'nv': 1, 'bcc': 2, 'akiec': 3, 'bkl': 4, 'df': 5, 'vasc': 6} 53 | print("Converting file {} ...".format(args.csv_file)) 54 | 55 | if args.pkl_file is not None: # 5 fold cross validation 56 | assert "Train" in args.csv_file, 'cross validation is only for training set.' 57 | with open(args.pkl_file, 'rb') as f: 58 | indices = pickle.load(f) 59 | for j in range(len(indices['trainIndCV'])): 60 | train_idx = indices['trainIndCV'][j] 61 | val_idx = indices['valIndCV'][j] 62 | new_annos = [] 63 | for ii in tqdm(range(len(train_idx))): 64 | i = train_idx[ii] 65 | image_id = csv_data.iloc[i]['image_id'] 66 | label = int(class_dict[csv_data.iloc[i]["dx"]]) 67 | derm_path = os.path.join(args.root, image_id + ".jpg") 68 | assert os.path.exists(derm_path), \ 69 | 'Image file does not exist: {}'.format(derm_path) 70 | sizes = Image.open(derm_path).size 71 | derm_width = sizes[0] 72 | derm_height = sizes[1] 73 | new_annos.append({"image_id": image_id, 74 | "category_id": label, 75 | "derm_height": derm_height, 76 | "derm_width": derm_width, 77 | "derm_path": derm_path}) 78 | converted_annos = {"annotations": new_annos, 79 | "num_classes": num_classes} 80 | save_path = os.path.join(args.sp, 81 | "converted_" + "ISIC_2018_Train_" + str(j) + ".json") 82 | print("Converted, Saving converted file to {}".format(save_path)) 83 | with open(save_path, "w") as f: 84 | json.dump(converted_annos, f) 85 | 86 | new_annos = [] 87 | for ii in tqdm(range(len(val_idx))): 88 | i = val_idx[ii] 89 | image_id = csv_data.iloc[i]['image_id'] 90 | label = int(class_dict[csv_data.iloc[i]["dx"]]) 91 | derm_path = os.path.join(args.root, image_id + ".jpg") 92 | assert os.path.exists(derm_path), \ 93 | 'Image file does not exist: {}'.format(derm_path) 94 | sizes = Image.open(derm_path).size 95 | derm_width = sizes[0] 96 | derm_height = sizes[1] 97 | new_annos.append({"image_id": image_id, 98 | "category_id": label, 99 | "derm_height": derm_height, 100 | "derm_width": derm_width, 101 | "derm_path": derm_path}) 102 | converted_annos = {"annotations": new_annos, 103 | "num_classes": num_classes} 104 | save_path = os.path.join(args.sp, 105 | "converted_" + "ISIC_2018_Val_" + str(j) + ".json") 106 | print("Converted, Saving converted file to {}".format(save_path)) 107 | with open(save_path, "w") as f: 108 | json.dump(converted_annos, f) 109 | else: # all images in the dataset are used 110 | annos = [] 111 | for i in tqdm(range(len(csv_data))): 112 | image_id = csv_data.iloc[i]['image_id'] 113 | if "Train" in args.csv_file: # for train 114 | label = int(class_dict[csv_data.iloc[i]["dx"]]) 115 | elif "Val" in args.csv_file: # for val 116 | label = int(csv_data.iloc[i]["MEL"]) \ 117 | + int(csv_data.iloc[i]["NV"]) * 2 \ 118 | + int(csv_data.iloc[i]["BCC"]) * 3 \ 119 | + int(csv_data.iloc[i]["AKIEC"]) * 4 \ 120 | + int(csv_data.iloc[i]["BKL"]) * 5 \ 121 | + int(csv_data.iloc[i]["DF"]) * 6 \ 122 | + int(csv_data.iloc[i]["VASC"]) * 7 \ 123 | - 1 124 | derm_path = os.path.join(args.root, image_id + ".jpg") 125 | assert os.path.exists(derm_path), \ 126 | 'Image file does not exist: {}'.format(derm_path) 127 | sizes = Image.open(derm_path).size 128 | derm_width = sizes[0] 129 | derm_height = sizes[1] 130 | if "Train" in args.csv_file or "Val" in args.csv_file: 131 | sample = {"image_id": image_id, 132 | "category_id": label, 133 | "derm_height": derm_height, 134 | "derm_width": derm_width, 135 | "derm_path": derm_path} 136 | else: 137 | sample = {"image_id": image_id, 138 | "derm_height": derm_height, 139 | "derm_width": derm_width, 140 | "derm_path": derm_path} 141 | annos.append(sample) 142 | converted_annos = {"annotations": annos, 143 | "num_classes": num_classes} 144 | save_path = os.path.join(args.sp, "converted_" + os.path.splitext(os.path.split(args.file)[-1])[0] + ".json") 145 | print("Converted, Saveing converted file to {}".format(save_path)) 146 | with open(save_path, "w") as f: 147 | json.dump(converted_annos, f) 148 | 149 | 150 | if __name__ == "__main__": 151 | args = parse_args() 152 | convert(args) 153 | -------------------------------------------------------------------------------- /tools/convert_from_ISIC_2019.py: -------------------------------------------------------------------------------- 1 | import json, os 2 | import argparse 3 | from tqdm import tqdm 4 | from PIL import Image 5 | import pandas as pd 6 | import pickle 7 | 8 | 9 | def parse_args(): 10 | ''' 11 | Before running this code, the code "resize_image_ISIC_2019.py" needs to be run first. 12 | example: python convert_from_ISIC_2019.py 13 | --csv_file ./dataset_files/ISIC_2019_Train.csv 14 | --pkl_file ./dataset_files/ISIC_2019_5foldcv_indices.pkl 15 | --root ./dataset_image/isic_2019/ISIC_2019_Train_Small/ 16 | --sp ../main/jsons/ 17 | ''' 18 | parser = argparse.ArgumentParser(description="Get the json file for ISIC 2019 dataset.") 19 | 20 | parser.add_argument( 21 | "--csv_file", 22 | help="csv file to be converted", 23 | required=True, 24 | type=str, 25 | ) 26 | parser.add_argument( 27 | "--pkl_file", 28 | help="pkl file to get the training and val index for cross validation", 29 | required=False, 30 | type=str, 31 | ) 32 | parser.add_argument( 33 | "--root", 34 | help="root path to the images", 35 | type=str, 36 | required=True, 37 | ) 38 | parser.add_argument( 39 | "--sp", 40 | help="save path for converted file ", 41 | type=str, 42 | required=False, 43 | default="." 44 | ) 45 | 46 | args = parser.parse_args() 47 | return args 48 | 49 | 50 | def convert(args): 51 | csv_data = pd.read_csv(args.csv_file) 52 | 53 | num_classes = 8 54 | if "Test" in args.csv_file: # the test set of ISIC 2019 adds a class "UNK" 55 | num_classes = 9 56 | print("Converting file {} ...".format(args.csv_file)) 57 | 58 | if args.pkl_file is not None: # 5 fold cross validation 59 | assert "Train" in args.csv_file, 'cross validation is only for training set.' 60 | with open(args.pkl_file, 'rb') as f: 61 | indices = pickle.load(f) 62 | for j in range(len(indices['trainIndCV'])): 63 | train_idx = indices['trainIndCV'][j] 64 | val_idx = indices['valIndCV'][j] 65 | new_annos = [] 66 | for ii in tqdm(range(len(train_idx))): 67 | i = train_idx[ii] 68 | image_id = csv_data.iloc[i]['image'] 69 | label = int(csv_data.iloc[i]["MEL"]) \ 70 | + int(csv_data.iloc[i]["NV"]) * 2 \ 71 | + int(csv_data.iloc[i]["BCC"]) * 3 \ 72 | + int(csv_data.iloc[i]["AK"]) * 4 \ 73 | + int(csv_data.iloc[i]["BKL"]) * 5 \ 74 | + int(csv_data.iloc[i]["DF"]) * 6 \ 75 | + int(csv_data.iloc[i]["VASC"]) * 7 \ 76 | + int(csv_data.iloc[i]["SCC"]) * 8 - 1 77 | 78 | derm_path = os.path.join(args.root, image_id + ".jpg") 79 | assert os.path.exists(derm_path), \ 80 | 'Image file does not exist: {}'.format(derm_path) 81 | sizes = Image.open(derm_path).size 82 | derm_width = sizes[0] 83 | derm_height = sizes[1] 84 | new_annos.append({"image_id": image_id, 85 | "category_id": label, 86 | "derm_height": derm_height, 87 | "derm_width": derm_width, 88 | "derm_path": derm_path}) 89 | converted_annos = {"annotations": new_annos, 90 | "num_classes": num_classes} 91 | save_path = os.path.join(args.sp, 92 | "converted_" + "ISIC_2019_Train_" + str(j) + ".json") 93 | print("Converted, Saving converted file to {}".format(save_path)) 94 | with open(save_path, "w") as f: 95 | json.dump(converted_annos, f) 96 | 97 | new_annos = [] 98 | for ii in tqdm(range(len(val_idx))): 99 | i = val_idx[ii] 100 | image_id = csv_data.iloc[i]['image'] 101 | label = int(csv_data.iloc[i]["MEL"]) \ 102 | + int(csv_data.iloc[i]["NV"]) * 2 \ 103 | + int(csv_data.iloc[i]["BCC"]) * 3 \ 104 | + int(csv_data.iloc[i]["AK"]) * 4 \ 105 | + int(csv_data.iloc[i]["BKL"]) * 5 \ 106 | + int(csv_data.iloc[i]["DF"]) * 6 \ 107 | + int(csv_data.iloc[i]["VASC"]) * 7 \ 108 | + int(csv_data.iloc[i]["SCC"]) * 8 - 1 109 | derm_path = os.path.join(args.root, image_id + ".jpg") 110 | assert os.path.exists(derm_path), \ 111 | 'Image file does not exist: {}'.format(derm_path) 112 | sizes = Image.open(derm_path).size 113 | derm_width = sizes[0] 114 | derm_height = sizes[1] 115 | new_annos.append({"image_id": image_id, 116 | "category_id": label, 117 | "derm_height": derm_height, 118 | "derm_width": derm_width, 119 | "derm_path": derm_path}) 120 | converted_annos = {"annotations": new_annos, 121 | "num_classes": num_classes} 122 | save_path = os.path.join(args.sp, 123 | "converted_" + "ISIC_2019_Val_" + str(j) + ".json") 124 | print("Converted, Saving converted file to {}".format(save_path)) 125 | with open(save_path, "w") as f: 126 | json.dump(converted_annos, f) 127 | else: # all images in the dataset are used 128 | annos = [] 129 | for i in tqdm(range(len(csv_data))): 130 | image_id = csv_data.iloc[i]['image'] 131 | if "Train" in args.csv_file or "Val" in args.csv_file: # for train and validation 132 | label = int(csv_data.iloc[i]["MEL"]) \ 133 | + int(csv_data.iloc[i]["NV"]) * 2 \ 134 | + int(csv_data.iloc[i]["BCC"]) * 3 \ 135 | + int(csv_data.iloc[i]["AK"]) * 4 \ 136 | + int(csv_data.iloc[i]["BKL"]) * 5 \ 137 | + int(csv_data.iloc[i]["DF"]) * 6 \ 138 | + int(csv_data.iloc[i]["VASC"]) * 7 \ 139 | + int(csv_data.iloc[i]["SCC"]) * 8 - 1 140 | 141 | derm_path = os.path.join(args.root, image_id + ".jpg") 142 | assert os.path.exists(derm_path), \ 143 | 'Image file does not exist: {}'.format(derm_path) 144 | 145 | sizes = Image.open(derm_path).size 146 | derm_width = sizes[0] 147 | derm_height = sizes[1] 148 | if "Train" in args.csv_file or "Val" in args.csv_file: 149 | sample = {"image_id": image_id, 150 | "category_id": label, 151 | "derm_height": derm_height, 152 | "derm_width": derm_width, 153 | "derm_path": derm_path} 154 | else: 155 | sample = {"image_id": image_id, 156 | "derm_height": derm_height, 157 | "derm_width": derm_width, 158 | "derm_path": derm_path} 159 | 160 | annos.append(sample) 161 | converted_annos = {"annotations": annos, 162 | "num_classes": num_classes} 163 | save_path = os.path.join(args.sp, "converted_" + os.path.splitext(os.path.split(args.csv_file)[-1])[0] + ".json") 164 | print("Converted, Saving converted file to {}".format(save_path)) 165 | with open(save_path, "w") as f: 166 | json.dump(converted_annos, f) 167 | 168 | 169 | if __name__ == "__main__": 170 | args = parse_args() 171 | convert(args) 172 | -------------------------------------------------------------------------------- /tools/dataset_files/ISIC_2017_Test.csv: -------------------------------------------------------------------------------- 1 | image_id,melanoma,seborrheic_keratosis,nv 2 | ISIC_0012086,0,1,0 3 | ISIC_0012092,0,0,1 4 | ISIC_0012095,0,0,1 5 | ISIC_0012134,0,1,0 6 | ISIC_0012136,0,1,0 7 | ISIC_0012147,0,0,1 8 | ISIC_0012149,0,0,1 9 | ISIC_0012152,0,0,1 10 | ISIC_0012178,0,1,0 11 | ISIC_0012199,0,1,0 12 | ISIC_0012207,0,1,0 13 | ISIC_0012215,0,1,0 14 | ISIC_0012216,0,0,1 15 | ISIC_0012223,0,1,0 16 | ISIC_0012240,0,1,0 17 | ISIC_0012248,0,1,0 18 | ISIC_0012258,1,0,0 19 | ISIC_0012265,0,1,0 20 | ISIC_0012266,0,1,0 21 | ISIC_0012272,0,1,0 22 | ISIC_0012273,0,1,0 23 | ISIC_0012314,0,1,0 24 | ISIC_0012323,0,1,0 25 | ISIC_0012330,0,1,0 26 | ISIC_0012356,1,0,0 27 | ISIC_0012357,0,0,1 28 | ISIC_0012358,0,1,0 29 | ISIC_0012364,0,1,0 30 | ISIC_0012369,1,0,0 31 | ISIC_0012372,0,1,0 32 | ISIC_0012375,0,1,0 33 | ISIC_0012387,0,1,0 34 | ISIC_0012388,0,1,0 35 | ISIC_0012395,1,0,0 36 | ISIC_0012414,0,1,0 37 | ISIC_0012425,1,0,0 38 | ISIC_0012428,0,1,0 39 | ISIC_0012432,0,1,0 40 | ISIC_0012447,0,1,0 41 | ISIC_0012448,0,1,0 42 | ISIC_0012484,0,0,1 43 | ISIC_0012493,0,0,1 44 | ISIC_0012510,0,1,0 45 | ISIC_0012522,0,1,0 46 | ISIC_0012537,0,1,0 47 | ISIC_0012548,0,1,0 48 | ISIC_0012551,0,0,1 49 | ISIC_0012654,0,0,1 50 | ISIC_0012656,0,0,1 51 | ISIC_0012705,0,1,0 52 | ISIC_0012708,0,0,1 53 | ISIC_0012722,0,0,1 54 | ISIC_0012757,0,1,0 55 | ISIC_0012758,1,0,0 56 | ISIC_0012786,0,1,0 57 | ISIC_0012803,0,0,1 58 | ISIC_0012836,0,0,1 59 | ISIC_0012837,0,0,1 60 | ISIC_0012848,0,1,0 61 | ISIC_0012852,0,1,0 62 | ISIC_0012903,0,0,1 63 | ISIC_0012904,0,0,1 64 | ISIC_0012928,0,1,0 65 | ISIC_0012941,0,0,1 66 | ISIC_0012955,0,1,0 67 | ISIC_0012967,0,0,1 68 | ISIC_0012974,0,1,0 69 | ISIC_0012989,1,0,0 70 | ISIC_0013030,0,1,0 71 | ISIC_0013035,0,1,0 72 | ISIC_0013045,0,0,1 73 | ISIC_0013070,0,0,1 74 | ISIC_0013072,1,0,0 75 | ISIC_0013073,1,0,0 76 | ISIC_0013085,0,1,0 77 | ISIC_0013109,0,0,1 78 | ISIC_0013159,0,0,1 79 | ISIC_0013164,0,0,1 80 | ISIC_0013169,0,1,0 81 | ISIC_0013170,0,1,0 82 | ISIC_0013176,0,0,1 83 | ISIC_0013191,0,0,1 84 | ISIC_0013203,0,1,0 85 | ISIC_0013216,0,0,1 86 | ISIC_0013226,0,0,1 87 | ISIC_0013230,0,0,1 88 | ISIC_0013242,1,0,0 89 | ISIC_0013269,0,0,1 90 | ISIC_0013270,0,1,0 91 | ISIC_0013271,0,1,0 92 | ISIC_0013277,1,0,0 93 | ISIC_0013281,0,1,0 94 | ISIC_0013291,0,0,1 95 | ISIC_0013319,0,1,0 96 | ISIC_0013321,1,0,0 97 | ISIC_0013325,0,0,1 98 | ISIC_0013374,1,0,0 99 | ISIC_0013393,0,1,0 100 | ISIC_0013399,0,0,1 101 | ISIC_0013411,1,0,0 102 | ISIC_0013414,1,0,0 103 | ISIC_0013416,0,0,1 104 | ISIC_0013455,1,0,0 105 | ISIC_0013457,1,0,0 106 | ISIC_0013459,1,0,0 107 | ISIC_0013465,0,1,0 108 | ISIC_0013472,1,0,0 109 | ISIC_0013473,1,0,0 110 | ISIC_0013511,0,0,1 111 | ISIC_0013512,0,0,1 112 | ISIC_0013529,0,0,1 113 | ISIC_0013565,1,0,0 114 | ISIC_0013577,1,0,0 115 | ISIC_0013588,1,0,0 116 | ISIC_0013600,0,0,1 117 | ISIC_0013602,0,0,1 118 | ISIC_0013615,1,0,0 119 | ISIC_0013617,1,0,0 120 | ISIC_0013636,1,0,0 121 | ISIC_0013673,0,1,0 122 | ISIC_0013678,1,0,0 123 | ISIC_0013696,1,0,0 124 | ISIC_0013708,0,1,0 125 | ISIC_0013733,1,0,0 126 | ISIC_0013738,0,0,1 127 | ISIC_0013739,1,0,0 128 | ISIC_0013764,0,1,0 129 | ISIC_0013766,1,0,0 130 | ISIC_0013767,1,0,0 131 | ISIC_0013794,0,0,1 132 | ISIC_0013809,0,0,1 133 | ISIC_0013813,1,0,0 134 | ISIC_0013814,1,0,0 135 | ISIC_0013833,1,0,0 136 | ISIC_0013842,1,0,0 137 | ISIC_0013867,1,0,0 138 | ISIC_0013891,0,0,1 139 | ISIC_0013897,0,0,1 140 | ISIC_0013908,1,0,0 141 | ISIC_0013911,0,0,1 142 | ISIC_0013917,1,0,0 143 | ISIC_0013925,1,0,0 144 | ISIC_0013948,1,0,0 145 | ISIC_0013953,1,0,0 146 | ISIC_0013966,0,0,1 147 | ISIC_0013977,0,1,0 148 | ISIC_0013987,1,0,0 149 | ISIC_0013988,1,0,0 150 | ISIC_0013998,0,0,1 151 | ISIC_0014006,0,1,0 152 | ISIC_0014027,1,0,0 153 | ISIC_0014059,1,0,0 154 | ISIC_0014077,1,0,0 155 | ISIC_0014090,0,0,1 156 | ISIC_0014103,1,0,0 157 | ISIC_0014110,1,0,0 158 | ISIC_0014117,0,0,1 159 | ISIC_0014129,1,0,0 160 | ISIC_0014148,1,0,0 161 | ISIC_0014160,1,0,0 162 | ISIC_0014177,0,1,0 163 | ISIC_0014181,1,0,0 164 | ISIC_0014186,1,0,0 165 | ISIC_0014219,1,0,0 166 | ISIC_0014221,1,0,0 167 | ISIC_0014233,1,0,0 168 | ISIC_0014251,0,1,0 169 | ISIC_0014255,1,0,0 170 | ISIC_0014270,1,0,0 171 | ISIC_0014278,0,1,0 172 | ISIC_0014284,1,0,0 173 | ISIC_0014288,1,0,0 174 | ISIC_0014319,1,0,0 175 | ISIC_0014336,1,0,0 176 | ISIC_0014349,1,0,0 177 | ISIC_0014369,1,0,0 178 | ISIC_0014386,0,1,0 179 | ISIC_0014392,0,1,0 180 | ISIC_0014409,0,1,0 181 | ISIC_0014419,0,1,0 182 | ISIC_0014423,1,0,0 183 | ISIC_0014434,1,0,0 184 | ISIC_0014454,1,0,0 185 | ISIC_0014457,0,1,0 186 | ISIC_0014470,0,0,1 187 | ISIC_0014474,0,1,0 188 | ISIC_0014478,1,0,0 189 | ISIC_0014489,1,0,0 190 | ISIC_0014500,0,1,0 191 | ISIC_0014503,0,1,0 192 | ISIC_0014506,1,0,0 193 | ISIC_0014513,1,0,0 194 | ISIC_0014541,1,0,0 195 | ISIC_0014542,1,0,0 196 | ISIC_0014546,1,0,0 197 | ISIC_0014548,1,0,0 198 | ISIC_0014559,1,0,0 199 | ISIC_0014567,0,1,0 200 | ISIC_0014574,0,1,0 201 | ISIC_0014575,0,1,0 202 | ISIC_0014586,0,1,0 203 | ISIC_0014587,0,1,0 204 | ISIC_0014588,0,1,0 205 | ISIC_0014590,0,1,0 206 | ISIC_0014600,0,1,0 207 | ISIC_0014619,0,1,0 208 | ISIC_0014626,0,1,0 209 | ISIC_0014627,0,1,0 210 | ISIC_0014629,0,1,0 211 | ISIC_0014631,0,1,0 212 | ISIC_0014634,0,1,0 213 | ISIC_0014643,0,1,0 214 | ISIC_0014644,0,1,0 215 | ISIC_0014645,0,1,0 216 | ISIC_0014647,0,1,0 217 | ISIC_0014648,0,1,0 218 | ISIC_0014649,0,1,0 219 | ISIC_0014652,0,1,0 220 | ISIC_0014653,0,1,0 221 | ISIC_0014663,1,0,0 222 | ISIC_0014666,1,0,0 223 | ISIC_0014675,0,0,1 224 | ISIC_0014677,0,0,1 225 | ISIC_0014687,0,0,1 226 | ISIC_0014693,0,0,1 227 | ISIC_0014695,1,0,0 228 | ISIC_0014697,0,0,1 229 | ISIC_0014698,0,0,1 230 | ISIC_0014703,1,0,0 231 | ISIC_0014720,0,0,1 232 | ISIC_0014725,0,0,1 233 | ISIC_0014727,1,0,0 234 | ISIC_0014728,0,0,1 235 | ISIC_0014729,0,0,1 236 | ISIC_0014740,0,0,1 237 | ISIC_0014743,0,0,1 238 | ISIC_0014746,0,0,1 239 | ISIC_0014749,0,0,1 240 | ISIC_0014753,0,0,1 241 | ISIC_0014755,0,0,1 242 | ISIC_0014765,0,0,1 243 | ISIC_0014766,1,0,0 244 | ISIC_0014768,0,0,1 245 | ISIC_0014772,1,0,0 246 | ISIC_0014773,0,0,1 247 | ISIC_0014780,0,0,1 248 | ISIC_0014784,1,0,0 249 | ISIC_0014786,0,0,1 250 | ISIC_0014787,0,0,1 251 | ISIC_0014790,1,0,0 252 | ISIC_0014792,0,0,1 253 | ISIC_0014796,0,0,1 254 | ISIC_0014798,0,0,1 255 | ISIC_0014800,1,0,0 256 | ISIC_0014807,0,0,1 257 | ISIC_0014814,0,0,1 258 | ISIC_0014815,0,0,1 259 | ISIC_0014820,0,0,1 260 | ISIC_0014822,0,0,1 261 | ISIC_0014826,1,0,0 262 | ISIC_0014833,0,0,1 263 | ISIC_0014835,0,0,1 264 | ISIC_0014844,0,0,1 265 | ISIC_0014853,0,0,1 266 | ISIC_0014854,0,0,1 267 | ISIC_0014862,1,0,0 268 | ISIC_0014863,0,0,1 269 | ISIC_0014867,0,0,1 270 | ISIC_0014868,0,0,1 271 | ISIC_0014872,1,0,0 272 | ISIC_0014876,0,0,1 273 | ISIC_0014879,0,0,1 274 | ISIC_0014883,1,0,0 275 | ISIC_0014901,0,0,1 276 | ISIC_0014907,0,0,1 277 | ISIC_0014910,0,0,1 278 | ISIC_0014912,1,0,0 279 | ISIC_0014921,0,0,1 280 | ISIC_0014927,0,0,1 281 | ISIC_0014928,1,0,0 282 | ISIC_0014932,1,0,0 283 | ISIC_0014936,0,0,1 284 | ISIC_0014938,0,0,1 285 | ISIC_0014940,0,0,1 286 | ISIC_0014941,0,0,1 287 | ISIC_0014942,0,0,1 288 | ISIC_0014943,0,0,1 289 | ISIC_0014944,0,0,1 290 | ISIC_0014947,0,0,1 291 | ISIC_0014948,0,0,1 292 | ISIC_0014949,0,0,1 293 | ISIC_0014952,0,0,1 294 | ISIC_0014955,0,0,1 295 | ISIC_0014956,0,0,1 296 | ISIC_0014957,0,0,1 297 | ISIC_0014958,0,0,1 298 | ISIC_0014959,0,0,1 299 | ISIC_0014961,0,0,1 300 | ISIC_0014962,0,0,1 301 | ISIC_0014963,1,0,0 302 | ISIC_0014964,0,0,1 303 | ISIC_0014966,0,0,1 304 | ISIC_0014968,0,0,1 305 | ISIC_0014969,0,0,1 306 | ISIC_0014973,0,0,1 307 | ISIC_0014974,0,0,1 308 | ISIC_0014977,0,0,1 309 | ISIC_0014982,1,0,0 310 | ISIC_0014992,0,0,1 311 | ISIC_0014994,0,0,1 312 | ISIC_0014998,0,0,1 313 | ISIC_0015002,0,0,1 314 | ISIC_0015003,0,0,1 315 | ISIC_0015004,1,0,0 316 | ISIC_0015007,0,0,1 317 | ISIC_0015008,0,0,1 318 | ISIC_0015009,0,0,1 319 | ISIC_0015011,0,0,1 320 | ISIC_0015013,0,0,1 321 | ISIC_0015015,0,0,1 322 | ISIC_0015016,0,0,1 323 | ISIC_0015018,0,0,1 324 | ISIC_0015019,0,0,1 325 | ISIC_0015020,0,0,1 326 | ISIC_0015021,0,0,1 327 | ISIC_0015023,0,0,1 328 | ISIC_0015026,0,0,1 329 | ISIC_0015030,0,0,1 330 | ISIC_0015031,0,0,1 331 | ISIC_0015034,0,0,1 332 | ISIC_0015035,0,0,1 333 | ISIC_0015037,0,0,1 334 | ISIC_0015040,0,0,1 335 | ISIC_0015041,1,0,0 336 | ISIC_0015046,1,0,0 337 | ISIC_0015050,1,0,0 338 | ISIC_0015051,0,0,1 339 | ISIC_0015056,0,0,1 340 | ISIC_0015057,0,0,1 341 | ISIC_0015060,0,0,1 342 | ISIC_0015064,0,0,1 343 | ISIC_0015071,1,0,0 344 | ISIC_0015078,0,0,1 345 | ISIC_0015089,0,0,1 346 | ISIC_0015102,0,0,1 347 | ISIC_0015115,1,0,0 348 | ISIC_0015118,0,0,1 349 | ISIC_0015119,1,0,0 350 | ISIC_0015125,0,0,1 351 | ISIC_0015127,1,0,0 352 | ISIC_0015129,0,0,1 353 | ISIC_0015130,0,0,1 354 | ISIC_0015132,1,0,0 355 | ISIC_0015133,1,0,0 356 | ISIC_0015136,1,0,0 357 | ISIC_0015139,0,0,1 358 | ISIC_0015140,0,0,1 359 | ISIC_0015142,1,0,0 360 | ISIC_0015146,0,0,1 361 | ISIC_0015149,0,0,1 362 | ISIC_0015150,0,0,1 363 | ISIC_0015152,0,0,1 364 | ISIC_0015155,0,0,1 365 | ISIC_0015156,1,0,0 366 | ISIC_0015157,0,0,1 367 | ISIC_0015160,0,0,1 368 | ISIC_0015161,0,0,1 369 | ISIC_0015163,1,0,0 370 | ISIC_0015167,1,0,0 371 | ISIC_0015171,0,0,1 372 | ISIC_0015173,0,0,1 373 | ISIC_0015174,0,0,1 374 | ISIC_0015175,0,0,1 375 | ISIC_0015176,0,0,1 376 | ISIC_0015179,0,0,1 377 | ISIC_0015180,1,0,0 378 | ISIC_0015184,0,0,1 379 | ISIC_0015185,1,0,0 380 | ISIC_0015193,1,0,0 381 | ISIC_0015201,0,0,1 382 | ISIC_0015202,0,0,1 383 | ISIC_0015203,0,0,1 384 | ISIC_0015206,1,0,0 385 | ISIC_0015207,0,0,1 386 | ISIC_0015208,0,0,1 387 | ISIC_0015212,0,0,1 388 | ISIC_0015215,0,0,1 389 | ISIC_0015216,0,0,1 390 | ISIC_0015217,0,0,1 391 | ISIC_0015218,0,0,1 392 | ISIC_0015223,0,0,1 393 | ISIC_0015224,0,0,1 394 | ISIC_0015226,0,0,1 395 | ISIC_0015229,1,0,0 396 | ISIC_0015232,0,0,1 397 | ISIC_0015237,0,0,1 398 | ISIC_0015241,0,0,1 399 | ISIC_0015244,0,0,1 400 | ISIC_0015245,0,0,1 401 | ISIC_0015250,0,0,1 402 | ISIC_0015251,1,0,0 403 | ISIC_0015254,0,0,1 404 | ISIC_0015255,0,0,1 405 | ISIC_0015258,0,0,1 406 | ISIC_0015264,0,0,1 407 | ISIC_0015270,0,0,1 408 | ISIC_0015273,0,0,1 409 | ISIC_0015274,0,0,1 410 | ISIC_0015276,0,0,1 411 | ISIC_0015279,0,0,1 412 | ISIC_0015283,0,0,1 413 | ISIC_0015291,0,0,1 414 | ISIC_0015293,0,0,1 415 | ISIC_0015298,0,0,1 416 | ISIC_0015309,0,0,1 417 | ISIC_0015310,0,0,1 418 | ISIC_0015311,0,0,1 419 | ISIC_0015312,0,0,1 420 | ISIC_0015330,0,0,1 421 | ISIC_0015331,0,0,1 422 | ISIC_0015347,0,0,1 423 | ISIC_0015353,0,0,1 424 | ISIC_0015355,0,0,1 425 | ISIC_0015357,0,0,1 426 | ISIC_0015360,0,0,1 427 | ISIC_0015363,0,0,1 428 | ISIC_0015364,0,0,1 429 | ISIC_0015368,0,0,1 430 | ISIC_0015369,0,0,1 431 | ISIC_0015383,0,0,1 432 | ISIC_0015386,0,0,1 433 | ISIC_0015390,0,0,1 434 | ISIC_0015395,0,0,1 435 | ISIC_0015403,0,0,1 436 | ISIC_0015404,0,0,1 437 | ISIC_0015411,0,0,1 438 | ISIC_0015412,0,0,1 439 | ISIC_0015416,0,0,1 440 | ISIC_0015417,0,0,1 441 | ISIC_0015418,0,0,1 442 | ISIC_0015419,0,0,1 443 | ISIC_0015436,0,0,1 444 | ISIC_0015440,0,0,1 445 | ISIC_0015447,0,0,1 446 | ISIC_0015455,0,0,1 447 | ISIC_0015464,0,0,1 448 | ISIC_0015466,0,0,1 449 | ISIC_0015468,0,0,1 450 | ISIC_0015476,0,0,1 451 | ISIC_0015481,0,0,1 452 | ISIC_0015482,0,0,1 453 | ISIC_0015485,0,0,1 454 | ISIC_0015510,0,0,1 455 | ISIC_0015526,0,0,1 456 | ISIC_0015537,0,0,1 457 | ISIC_0015544,0,0,1 458 | ISIC_0015559,0,0,1 459 | ISIC_0015563,0,0,1 460 | ISIC_0015566,0,0,1 461 | ISIC_0015568,0,0,1 462 | ISIC_0015582,0,0,1 463 | ISIC_0015593,0,0,1 464 | ISIC_0015603,0,0,1 465 | ISIC_0015607,0,0,1 466 | ISIC_0015614,0,0,1 467 | ISIC_0015617,0,0,1 468 | ISIC_0015625,0,0,1 469 | ISIC_0015631,0,0,1 470 | ISIC_0015636,0,0,1 471 | ISIC_0015638,0,0,1 472 | ISIC_0015641,0,0,1 473 | ISIC_0015645,0,0,1 474 | ISIC_0015936,0,0,1 475 | ISIC_0015937,0,0,1 476 | ISIC_0015938,0,0,1 477 | ISIC_0015939,0,0,1 478 | ISIC_0015940,0,0,1 479 | ISIC_0015941,0,0,1 480 | ISIC_0015942,0,0,1 481 | ISIC_0015943,0,0,1 482 | ISIC_0015944,0,0,1 483 | ISIC_0015945,0,0,1 484 | ISIC_0015946,0,0,1 485 | ISIC_0015947,0,0,1 486 | ISIC_0015948,0,0,1 487 | ISIC_0015949,0,0,1 488 | ISIC_0015950,0,0,1 489 | ISIC_0015951,0,0,1 490 | ISIC_0015952,0,0,1 491 | ISIC_0015953,0,0,1 492 | ISIC_0015954,0,0,1 493 | ISIC_0015955,0,0,1 494 | ISIC_0015956,0,0,1 495 | ISIC_0015957,0,0,1 496 | ISIC_0015958,0,0,1 497 | ISIC_0015959,0,0,1 498 | ISIC_0015960,0,0,1 499 | ISIC_0015961,0,0,1 500 | ISIC_0015962,0,0,1 501 | ISIC_0015963,0,0,1 502 | ISIC_0015964,0,0,1 503 | ISIC_0015965,0,0,1 504 | ISIC_0015966,0,0,1 505 | ISIC_0015967,0,0,1 506 | ISIC_0015968,0,0,1 507 | ISIC_0015969,0,0,1 508 | ISIC_0015971,0,0,1 509 | ISIC_0015972,0,0,1 510 | ISIC_0015973,0,0,1 511 | ISIC_0015974,0,0,1 512 | ISIC_0015975,0,0,1 513 | ISIC_0015976,0,0,1 514 | ISIC_0015978,0,0,1 515 | ISIC_0015979,0,0,1 516 | ISIC_0015980,0,0,1 517 | ISIC_0015981,0,0,1 518 | ISIC_0015982,0,0,1 519 | ISIC_0015983,0,0,1 520 | ISIC_0015984,0,0,1 521 | ISIC_0015985,0,0,1 522 | ISIC_0015986,0,0,1 523 | ISIC_0015987,0,0,1 524 | ISIC_0015988,0,0,1 525 | ISIC_0015989,0,0,1 526 | ISIC_0015990,0,0,1 527 | ISIC_0015991,0,0,1 528 | ISIC_0015992,0,0,1 529 | ISIC_0015993,0,0,1 530 | ISIC_0015994,0,0,1 531 | ISIC_0015995,0,0,1 532 | ISIC_0015996,0,0,1 533 | ISIC_0015997,0,0,1 534 | ISIC_0015998,0,0,1 535 | ISIC_0015999,0,0,1 536 | ISIC_0016000,0,0,1 537 | ISIC_0016001,0,0,1 538 | ISIC_0016002,0,0,1 539 | ISIC_0016003,0,0,1 540 | ISIC_0016004,0,0,1 541 | ISIC_0016005,0,0,1 542 | ISIC_0016006,0,0,1 543 | ISIC_0016007,0,0,1 544 | ISIC_0016008,0,0,1 545 | ISIC_0016009,0,0,1 546 | ISIC_0016011,0,0,1 547 | ISIC_0016012,0,0,1 548 | ISIC_0016013,0,0,1 549 | ISIC_0016014,0,0,1 550 | ISIC_0016015,0,0,1 551 | ISIC_0016016,0,0,1 552 | ISIC_0016017,0,0,1 553 | ISIC_0016018,0,0,1 554 | ISIC_0016019,0,0,1 555 | ISIC_0016022,0,0,1 556 | ISIC_0016023,0,0,1 557 | ISIC_0016024,0,0,1 558 | ISIC_0016025,0,0,1 559 | ISIC_0016026,0,0,1 560 | ISIC_0016027,0,0,1 561 | ISIC_0016028,0,0,1 562 | ISIC_0016029,0,0,1 563 | ISIC_0016030,0,0,1 564 | ISIC_0016031,0,0,1 565 | ISIC_0016033,0,0,1 566 | ISIC_0016034,0,0,1 567 | ISIC_0016035,0,0,1 568 | ISIC_0016036,0,0,1 569 | ISIC_0016037,0,0,1 570 | ISIC_0016038,0,0,1 571 | ISIC_0016040,0,0,1 572 | ISIC_0016041,0,0,1 573 | ISIC_0016042,0,0,1 574 | ISIC_0016043,0,0,1 575 | ISIC_0016044,0,0,1 576 | ISIC_0016045,0,0,1 577 | ISIC_0016046,0,0,1 578 | ISIC_0016048,0,0,1 579 | ISIC_0016049,0,0,1 580 | ISIC_0016050,0,0,1 581 | ISIC_0016051,0,0,1 582 | ISIC_0016052,0,0,1 583 | ISIC_0016053,0,0,1 584 | ISIC_0016054,0,0,1 585 | ISIC_0016055,0,0,1 586 | ISIC_0016056,0,0,1 587 | ISIC_0016057,0,0,1 588 | ISIC_0016058,0,0,1 589 | ISIC_0016059,0,0,1 590 | ISIC_0016060,0,0,1 591 | ISIC_0016061,0,0,1 592 | ISIC_0016062,0,0,1 593 | ISIC_0016063,0,0,1 594 | ISIC_0016064,0,0,1 595 | ISIC_0016065,0,0,1 596 | ISIC_0016066,0,0,1 597 | ISIC_0016068,0,0,1 598 | ISIC_0016069,0,0,1 599 | ISIC_0016070,0,0,1 600 | ISIC_0016071,0,0,1 601 | ISIC_0016072,0,0,1 602 | -------------------------------------------------------------------------------- /tools/dataset_files/ISIC_2017_Val.csv: -------------------------------------------------------------------------------- 1 | image_id,melanoma,seborrheic_keratosis,nv 2 | ISIC_0001769,0,0,1 3 | ISIC_0001852,0,0,1 4 | ISIC_0001871,0,0,1 5 | ISIC_0003462,0,0,1 6 | ISIC_0003539,0,0,1 7 | ISIC_0003582,0,0,1 8 | ISIC_0003657,0,0,1 9 | ISIC_0003805,0,0,1 10 | ISIC_0004337,0,0,1 11 | ISIC_0006651,0,0,1 12 | ISIC_0006671,0,0,1 13 | ISIC_0006815,0,0,1 14 | ISIC_0006914,0,0,1 15 | ISIC_0007141,0,0,1 16 | ISIC_0007156,0,0,1 17 | ISIC_0007235,0,0,1 18 | ISIC_0007241,0,0,1 19 | ISIC_0007332,0,0,1 20 | ISIC_0007344,0,0,1 21 | ISIC_0007528,0,0,1 22 | ISIC_0007796,0,0,1 23 | ISIC_0008025,0,0,1 24 | ISIC_0008524,0,0,1 25 | ISIC_0009995,0,0,1 26 | ISIC_0010459,0,0,1 27 | ISIC_0012099,1,0,0 28 | ISIC_0012109,0,0,1 29 | ISIC_0012126,0,0,1 30 | ISIC_0012127,0,0,1 31 | ISIC_0012143,0,1,0 32 | ISIC_0012151,1,0,0 33 | ISIC_0012159,0,0,1 34 | ISIC_0012160,0,0,1 35 | ISIC_0012191,0,0,1 36 | ISIC_0012201,0,0,1 37 | ISIC_0012204,0,1,0 38 | ISIC_0012206,0,0,1 39 | ISIC_0012210,0,1,0 40 | ISIC_0012221,0,0,1 41 | ISIC_0012222,0,0,1 42 | ISIC_0012254,0,1,0 43 | ISIC_0012256,0,0,1 44 | ISIC_0012288,1,0,0 45 | ISIC_0012306,0,0,1 46 | ISIC_0012313,0,0,1 47 | ISIC_0012316,0,0,1 48 | ISIC_0012335,0,0,1 49 | ISIC_0012380,0,1,0 50 | ISIC_0012383,0,1,0 51 | ISIC_0012400,0,0,1 52 | ISIC_0012417,0,1,0 53 | ISIC_0012434,1,0,0 54 | ISIC_0012492,0,1,0 55 | ISIC_0012513,0,1,0 56 | ISIC_0012538,0,0,1 57 | ISIC_0012547,0,0,1 58 | ISIC_0012660,0,0,1 59 | ISIC_0012684,0,0,1 60 | ISIC_0012720,0,1,0 61 | ISIC_0012746,0,0,1 62 | ISIC_0012876,0,0,1 63 | ISIC_0012927,0,1,0 64 | ISIC_0012956,0,0,1 65 | ISIC_0012959,0,1,0 66 | ISIC_0012965,0,0,1 67 | ISIC_0013010,0,0,1 68 | ISIC_0013082,0,0,1 69 | ISIC_0013104,0,0,1 70 | ISIC_0013127,0,1,0 71 | ISIC_0013128,0,0,1 72 | ISIC_0013132,0,0,1 73 | ISIC_0013188,0,0,1 74 | ISIC_0013215,0,1,0 75 | ISIC_0013232,1,0,0 76 | ISIC_0013421,0,1,0 77 | ISIC_0013491,1,0,0 78 | ISIC_0013501,1,0,0 79 | ISIC_0013518,1,0,0 80 | ISIC_0013527,0,0,1 81 | ISIC_0013549,1,0,0 82 | ISIC_0013561,0,0,1 83 | ISIC_0013562,0,0,1 84 | ISIC_0013632,0,1,0 85 | ISIC_0013637,0,1,0 86 | ISIC_0013644,1,0,0 87 | ISIC_0013651,1,0,0 88 | ISIC_0013663,1,0,0 89 | ISIC_0013702,1,0,0 90 | ISIC_0013736,1,0,0 91 | ISIC_0013793,0,0,1 92 | ISIC_0013828,1,0,0 93 | ISIC_0013863,0,1,0 94 | ISIC_0013898,0,0,1 95 | ISIC_0013945,0,1,0 96 | ISIC_0014037,1,0,0 97 | ISIC_0014038,0,1,0 98 | ISIC_0014055,0,1,0 99 | ISIC_0014139,0,1,0 100 | ISIC_0014162,0,0,1 101 | ISIC_0014178,0,0,1 102 | ISIC_0014211,0,0,1 103 | ISIC_0014212,0,1,0 104 | ISIC_0014217,1,0,0 105 | ISIC_0014302,1,0,0 106 | ISIC_0014310,0,1,0 107 | ISIC_0014382,0,1,0 108 | ISIC_0014428,1,0,0 109 | ISIC_0014558,1,0,0 110 | ISIC_0014568,0,1,0 111 | ISIC_0014572,0,1,0 112 | ISIC_0014597,0,1,0 113 | ISIC_0014601,0,1,0 114 | ISIC_0014608,0,1,0 115 | ISIC_0014610,0,1,0 116 | ISIC_0014611,0,1,0 117 | ISIC_0014616,0,1,0 118 | ISIC_0014618,0,1,0 119 | ISIC_0014620,0,1,0 120 | ISIC_0014623,0,1,0 121 | ISIC_0014624,0,1,0 122 | ISIC_0014633,0,1,0 123 | ISIC_0014635,0,1,0 124 | ISIC_0014637,0,1,0 125 | ISIC_0014688,1,0,0 126 | ISIC_0014712,0,1,0 127 | ISIC_0014809,1,0,0 128 | ISIC_0014829,0,0,1 129 | ISIC_0014857,1,0,0 130 | ISIC_0014931,1,0,0 131 | ISIC_0014937,0,0,1 132 | ISIC_0014945,0,0,1 133 | ISIC_0014946,1,0,0 134 | ISIC_0014979,1,0,0 135 | ISIC_0014985,1,0,0 136 | ISIC_0014989,0,0,1 137 | ISIC_0015043,0,0,1 138 | ISIC_0015062,0,1,0 139 | ISIC_0015124,1,0,0 140 | ISIC_0015144,0,0,1 141 | ISIC_0015211,0,0,1 142 | ISIC_0015243,1,0,0 143 | ISIC_0015256,1,0,0 144 | ISIC_0015313,0,0,1 145 | ISIC_0015372,0,0,1 146 | ISIC_0015401,0,0,1 147 | ISIC_0015443,0,0,1 148 | ISIC_0015445,0,0,1 149 | ISIC_0015483,0,0,1 150 | ISIC_0015496,0,0,1 151 | ISIC_0015627,0,0,1 152 | -------------------------------------------------------------------------------- /tools/dataset_files/ISIC_2018_5foldcv_indices.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaopengUSTC/mbit-skin-cancer/a82a87b2abebaf724dbe2a7b7e833c434c1b56a0/tools/dataset_files/ISIC_2018_5foldcv_indices.pkl -------------------------------------------------------------------------------- /tools/dataset_files/ISIC_2018_Val.csv: -------------------------------------------------------------------------------- 1 | image_id,MEL,NV,BCC,AKIEC,BKL,DF,VASC 2 | ISIC_0034321,0,1,0,0,0,0,0 3 | ISIC_0034322,0,1,0,0,0,0,0 4 | ISIC_0034323,0,0,1,0,0,0,0 5 | ISIC_0034324,0,1,0,0,0,0,0 6 | ISIC_0034325,0,1,0,0,0,0,0 7 | ISIC_0034326,0,0,0,0,1,0,0 8 | ISIC_0034328,0,1,0,0,0,0,0 9 | ISIC_0034329,1,0,0,0,0,0,0 10 | ISIC_0034330,0,1,0,0,0,0,0 11 | ISIC_0034331,0,1,0,0,0,0,0 12 | ISIC_0034332,0,0,0,1,0,0,0 13 | ISIC_0034333,0,0,1,0,0,0,0 14 | ISIC_0034334,0,0,0,0,0,1,0 15 | ISIC_0034335,0,1,0,0,0,0,0 16 | ISIC_0034336,0,1,0,0,0,0,0 17 | ISIC_0034337,0,1,0,0,0,0,0 18 | ISIC_0034338,0,0,1,0,0,0,0 19 | ISIC_0034339,0,1,0,0,0,0,0 20 | ISIC_0034340,0,1,0,0,0,0,0 21 | ISIC_0034341,0,1,0,0,0,0,0 22 | ISIC_0034342,0,1,0,0,0,0,0 23 | ISIC_0034343,1,0,0,0,0,0,0 24 | ISIC_0034344,0,0,1,0,0,0,0 25 | ISIC_0034345,0,0,0,0,1,0,0 26 | ISIC_0034346,0,0,1,0,0,0,0 27 | ISIC_0034347,0,1,0,0,0,0,0 28 | ISIC_0034348,0,1,0,0,0,0,0 29 | ISIC_0034349,0,1,0,0,0,0,0 30 | ISIC_0034350,0,1,0,0,0,0,0 31 | ISIC_0034351,0,1,0,0,0,0,0 32 | ISIC_0034352,0,1,0,0,0,0,0 33 | ISIC_0034354,1,0,0,0,0,0,0 34 | ISIC_0034355,0,1,0,0,0,0,0 35 | ISIC_0034356,0,1,0,0,0,0,0 36 | ISIC_0034357,0,1,0,0,0,0,0 37 | ISIC_0034359,0,1,0,0,0,0,0 38 | ISIC_0034360,0,0,0,0,1,0,0 39 | ISIC_0034361,0,0,1,0,0,0,0 40 | ISIC_0034362,0,0,0,0,1,0,0 41 | ISIC_0034363,0,1,0,0,0,0,0 42 | ISIC_0034364,0,1,0,0,0,0,0 43 | ISIC_0034365,0,1,0,0,0,0,0 44 | ISIC_0034366,0,0,0,0,1,0,0 45 | ISIC_0034367,0,1,0,0,0,0,0 46 | ISIC_0034368,0,0,0,0,1,0,0 47 | ISIC_0034369,0,1,0,0,0,0,0 48 | ISIC_0034370,0,1,0,0,0,0,0 49 | ISIC_0034371,0,0,0,0,1,0,0 50 | ISIC_0034372,0,1,0,0,0,0,0 51 | ISIC_0034374,0,1,0,0,0,0,0 52 | ISIC_0034375,0,0,0,0,1,0,0 53 | ISIC_0034376,1,0,0,0,0,0,0 54 | ISIC_0034377,0,1,0,0,0,0,0 55 | ISIC_0034378,0,1,0,0,0,0,0 56 | ISIC_0034379,0,1,0,0,0,0,0 57 | ISIC_0034380,0,1,0,0,0,0,0 58 | ISIC_0034381,1,0,0,0,0,0,0 59 | ISIC_0034382,1,0,0,0,0,0,0 60 | ISIC_0034383,0,0,1,0,0,0,0 61 | ISIC_0034385,0,1,0,0,0,0,0 62 | ISIC_0034386,1,0,0,0,0,0,0 63 | ISIC_0034387,0,0,0,0,1,0,0 64 | ISIC_0034389,0,1,0,0,0,0,0 65 | ISIC_0034390,0,0,0,0,1,0,0 66 | ISIC_0034391,0,1,0,0,0,0,0 67 | ISIC_0034392,0,1,0,0,0,0,0 68 | ISIC_0034393,0,1,0,0,0,0,0 69 | ISIC_0034394,1,0,0,0,0,0,0 70 | ISIC_0034395,0,1,0,0,0,0,0 71 | ISIC_0034396,0,0,0,1,0,0,0 72 | ISIC_0034397,0,1,0,0,0,0,0 73 | ISIC_0034398,1,0,0,0,0,0,0 74 | ISIC_0034399,0,1,0,0,0,0,0 75 | ISIC_0034400,0,1,0,0,0,0,0 76 | ISIC_0034401,0,1,0,0,0,0,0 77 | ISIC_0034402,0,0,0,1,0,0,0 78 | ISIC_0034403,0,1,0,0,0,0,0 79 | ISIC_0034404,0,0,1,0,0,0,0 80 | ISIC_0034405,0,0,1,0,0,0,0 81 | ISIC_0034406,0,0,1,0,0,0,0 82 | ISIC_0034407,0,1,0,0,0,0,0 83 | ISIC_0034408,0,1,0,0,0,0,0 84 | ISIC_0034409,0,0,1,0,0,0,0 85 | ISIC_0034410,0,0,0,1,0,0,0 86 | ISIC_0034411,0,0,0,0,1,0,0 87 | ISIC_0034412,0,1,0,0,0,0,0 88 | ISIC_0034413,0,0,0,0,1,0,0 89 | ISIC_0034414,0,1,0,0,0,0,0 90 | ISIC_0034415,0,1,0,0,0,0,0 91 | ISIC_0034416,0,0,1,0,0,0,0 92 | ISIC_0034417,0,1,0,0,0,0,0 93 | ISIC_0034418,0,1,0,0,0,0,0 94 | ISIC_0034419,0,1,0,0,0,0,0 95 | ISIC_0034420,0,1,0,0,0,0,0 96 | ISIC_0034421,0,0,0,1,0,0,0 97 | ISIC_0034422,0,0,0,1,0,0,0 98 | ISIC_0034423,0,1,0,0,0,0,0 99 | ISIC_0034424,0,1,0,0,0,0,0 100 | ISIC_0034425,0,1,0,0,0,0,0 101 | ISIC_0034426,0,1,0,0,0,0,0 102 | ISIC_0034427,0,0,0,1,0,0,0 103 | ISIC_0034428,0,1,0,0,0,0,0 104 | ISIC_0034429,0,1,0,0,0,0,0 105 | ISIC_0034430,0,1,0,0,0,0,0 106 | ISIC_0034431,0,1,0,0,0,0,0 107 | ISIC_0034433,0,1,0,0,0,0,0 108 | ISIC_0034434,0,1,0,0,0,0,0 109 | ISIC_0034435,0,1,0,0,0,0,0 110 | ISIC_0034436,0,0,0,1,0,0,0 111 | ISIC_0034437,0,1,0,0,0,0,0 112 | ISIC_0034438,1,0,0,0,0,0,0 113 | ISIC_0034439,0,1,0,0,0,0,0 114 | ISIC_0034440,0,1,0,0,0,0,0 115 | ISIC_0034441,0,1,0,0,0,0,0 116 | ISIC_0034442,0,1,0,0,0,0,0 117 | ISIC_0034443,0,1,0,0,0,0,0 118 | ISIC_0034444,0,1,0,0,0,0,0 119 | ISIC_0034445,0,1,0,0,0,0,0 120 | ISIC_0034446,1,0,0,0,0,0,0 121 | ISIC_0034447,0,1,0,0,0,0,0 122 | ISIC_0034448,0,1,0,0,0,0,0 123 | ISIC_0034449,0,1,0,0,0,0,0 124 | ISIC_0034450,0,1,0,0,0,0,0 125 | ISIC_0034451,0,0,0,0,1,0,0 126 | ISIC_0034452,0,1,0,0,0,0,0 127 | ISIC_0034453,0,0,0,0,1,0,0 128 | ISIC_0034454,0,1,0,0,0,0,0 129 | ISIC_0034455,0,0,0,0,0,0,1 130 | ISIC_0034456,0,1,0,0,0,0,0 131 | ISIC_0034457,1,0,0,0,0,0,0 132 | ISIC_0034458,0,1,0,0,0,0,0 133 | ISIC_0034459,1,0,0,0,0,0,0 134 | ISIC_0034460,0,0,0,0,1,0,0 135 | ISIC_0034461,0,1,0,0,0,0,0 136 | ISIC_0034463,0,1,0,0,0,0,0 137 | ISIC_0034464,0,1,0,0,0,0,0 138 | ISIC_0034465,0,1,0,0,0,0,0 139 | ISIC_0034466,0,1,0,0,0,0,0 140 | ISIC_0034467,0,1,0,0,0,0,0 141 | ISIC_0034468,0,1,0,0,0,0,0 142 | ISIC_0034469,0,1,0,0,0,0,0 143 | ISIC_0034470,0,0,0,0,1,0,0 144 | ISIC_0034471,0,0,0,0,0,0,1 145 | ISIC_0034472,1,0,0,0,0,0,0 146 | ISIC_0034474,0,1,0,0,0,0,0 147 | ISIC_0034475,0,1,0,0,0,0,0 148 | ISIC_0034476,0,1,0,0,0,0,0 149 | ISIC_0034477,1,0,0,0,0,0,0 150 | ISIC_0034478,0,0,1,0,0,0,0 151 | ISIC_0034480,0,1,0,0,0,0,0 152 | ISIC_0034481,0,1,0,0,0,0,0 153 | ISIC_0034482,1,0,0,0,0,0,0 154 | ISIC_0034483,0,1,0,0,0,0,0 155 | ISIC_0034484,0,1,0,0,0,0,0 156 | ISIC_0034485,0,0,0,0,1,0,0 157 | ISIC_0034486,0,0,1,0,0,0,0 158 | ISIC_0034487,1,0,0,0,0,0,0 159 | ISIC_0034488,0,1,0,0,0,0,0 160 | ISIC_0034489,0,1,0,0,0,0,0 161 | ISIC_0034490,0,0,0,0,1,0,0 162 | ISIC_0034491,0,1,0,0,0,0,0 163 | ISIC_0034492,1,0,0,0,0,0,0 164 | ISIC_0034493,0,0,0,0,1,0,0 165 | ISIC_0034494,1,0,0,0,0,0,0 166 | ISIC_0034495,0,1,0,0,0,0,0 167 | ISIC_0034496,0,1,0,0,0,0,0 168 | ISIC_0034497,1,0,0,0,0,0,0 169 | ISIC_0034498,0,1,0,0,0,0,0 170 | ISIC_0034499,0,1,0,0,0,0,0 171 | ISIC_0034500,0,0,0,0,1,0,0 172 | ISIC_0034501,0,1,0,0,0,0,0 173 | ISIC_0034502,0,1,0,0,0,0,0 174 | ISIC_0034503,0,1,0,0,0,0,0 175 | ISIC_0034504,1,0,0,0,0,0,0 176 | ISIC_0034505,0,0,0,0,1,0,0 177 | ISIC_0034506,0,1,0,0,0,0,0 178 | ISIC_0034507,0,1,0,0,0,0,0 179 | ISIC_0034508,0,0,0,0,0,0,1 180 | ISIC_0034509,0,1,0,0,0,0,0 181 | ISIC_0034510,0,1,0,0,0,0,0 182 | ISIC_0034511,0,1,0,0,0,0,0 183 | ISIC_0034512,0,1,0,0,0,0,0 184 | ISIC_0034513,0,1,0,0,0,0,0 185 | ISIC_0034514,0,1,0,0,0,0,0 186 | ISIC_0034515,0,1,0,0,0,0,0 187 | ISIC_0034516,0,1,0,0,0,0,0 188 | ISIC_0034517,0,1,0,0,0,0,0 189 | ISIC_0034518,0,1,0,0,0,0,0 190 | ISIC_0034519,0,1,0,0,0,0,0 191 | ISIC_0034520,0,1,0,0,0,0,0 192 | ISIC_0034521,0,0,0,0,1,0,0 193 | ISIC_0034522,0,1,0,0,0,0,0 194 | ISIC_0034523,0,0,1,0,0,0,0 195 | -------------------------------------------------------------------------------- /tools/resize_image_ISIC_2019.py: -------------------------------------------------------------------------------- 1 | import json, os 2 | import argparse 3 | from tqdm import tqdm 4 | from PIL import Image 5 | import torchvision.transforms as transforms 6 | import pandas as pd 7 | import numpy as np 8 | 9 | 10 | def parse_args(): 11 | ''' 12 | Many images of ISIC 2019 have black borders or are too large. The black borders need to be removed, 13 | and the images need to be resize to a fixed size. 14 | example: python resize_image_ISIC_2019.py 15 | --csv_file ./dataset_files/ISIC_2019_Train.csv 16 | --root /SDG/work_image/image/skin_cancer/ISIC2019/ISIC_2019_Training_Input/ 17 | --sp /home/yp/4T/jsons 18 | --small_path ./dataset_image/isic_2019/ISIC_2019_Train_Small/ 19 | ''' 20 | parser = argparse.ArgumentParser(description="Resize the images of ISIC 2019 dataset.") 21 | 22 | parser.add_argument( 23 | "--csv_file", 24 | help="csv file to be converted", 25 | required=True, 26 | type=str, 27 | ) 28 | parser.add_argument( 29 | "--root", 30 | help="root path to save image", 31 | type=str, 32 | required=True, 33 | ) 34 | parser.add_argument( 35 | "--sp", 36 | help="save path for converted file ", 37 | type=str, 38 | required=False, 39 | default="." 40 | ) 41 | parser.add_argument( 42 | "--small_path", 43 | help="save path for small images", 44 | type=str, 45 | required=True, 46 | default="." 47 | ) 48 | 49 | args = parser.parse_args() 50 | return args 51 | 52 | 53 | def convert(args): 54 | csv_data = pd.read_csv(args.csv_file) 55 | 56 | print("Converting file {} ...".format(args.csv_file)) 57 | 58 | for i in tqdm(range(len(csv_data))): 59 | image_id = csv_data.iloc[i]['image'] 60 | derm_path = os.path.join(args.root, image_id + ".jpg") 61 | assert os.path.exists(derm_path), \ 62 | 'Image file does not exist: {}'.format(derm_path) 63 | 64 | img = Image.open(derm_path) 65 | min_size = min(img.size) 66 | croping = transforms.CenterCrop(min_size) 67 | img = croping(img) # The image is cropped to a square based on the short side. 68 | 69 | # Remove the black borders 70 | threshold = 40 71 | img = np.array(img) 72 | 73 | ll = 1 # The most edge line may be bright, so start searching from the second line. 74 | while True: 75 | img_ll = img[ll:ll+1, :, :] 76 | if np.max(img_ll) < threshold: 77 | ll += 1 78 | else: 79 | break 80 | if ll > 1: 81 | img = img[ll:, :, :] 82 | 83 | ll = 1 84 | while True: 85 | img_ll = img[-1-ll:-ll, :, :] 86 | if np.max(img_ll) < threshold: 87 | ll += 1 88 | else: 89 | break 90 | if ll > 1: 91 | img = img[:-ll, :, :] 92 | 93 | ll = 1 94 | while True: 95 | img_ll = img[:, ll:ll+1, :] 96 | if np.max(img_ll) < threshold: 97 | ll += 1 98 | else: 99 | break 100 | if ll > 1: 101 | img = img[:, ll:, :] 102 | 103 | ll = 1 104 | while True: 105 | img_ll = img[:, -1-ll:-ll, :] 106 | if np.max(img_ll) < threshold: 107 | ll += 1 108 | else: 109 | break 110 | if ll > 1: 111 | img = img[:, :-ll, :] 112 | 113 | # Determine whether the four corners of the image are dark, if so, further cropping is needed. 114 | step = 10 115 | img_1 = img 116 | c_l_all, c_r_all, c_t_all, c_b_all = 0, 0, 0, 0 117 | while True: 118 | h, w = img.shape[0], img.shape[1] 119 | c_l, c_r, c_t, c_b = 0, 0, 0, 0 120 | img_l_t = img[1:step, 1:step, :] 121 | img_r_t = img[1:step, w-step:w-1, :] 122 | img_l_b = img[h-step:h-1, 1:step, :] 123 | img_r_b = img[h-step:h-1, w-step:w-1, :] 124 | if np.max(img_l_t) < threshold: 125 | c_l, c_t = step, step 126 | if np.max(img_r_t) < threshold: 127 | c_r, c_t = step, step 128 | if np.max(img_l_b) < threshold: 129 | c_l, c_b = step, step 130 | if np.max(img_r_b) < threshold: 131 | c_r, c_b = step, step 132 | 133 | if c_l > 0 or c_r > 0: 134 | img = img[c_t:h-c_b, c_l:w-c_r, :] 135 | c_l_all += c_l 136 | c_r_all += c_r 137 | c_t_all += c_t 138 | c_b_all += c_b 139 | else: 140 | break 141 | min_size = min(img.shape[0], img.shape[1]) 142 | aug_size = int(min_size * 0.05) 143 | c_l_all = max(0, c_l_all - aug_size) 144 | c_r_all = max(0, c_r_all - aug_size) 145 | c_t_all = max(0, c_t_all - aug_size) 146 | c_b_all = max(0, c_b_all - aug_size) 147 | h, w = img_1.shape[0], img_1.shape[1] 148 | # A few images may be darker overall, so there is no need to crop. 149 | if c_l_all > h * 0.3 or c_r_all > h * 0.3 or c_t_all > h * 0.3 or c_b_all > h * 0.3: 150 | img = img_1 151 | else: 152 | img = img_1[c_t_all: h - c_b_all, c_l_all: w - c_r_all, :] 153 | 154 | img = Image.fromarray(img) 155 | min_size = min(img.size) 156 | croping = transforms.CenterCrop(min_size) 157 | img = croping(img) # The image is cropped to a square based on the short side again. 158 | 159 | # the input image resize to a fix size 160 | resizing = transforms.Resize(450) 161 | img = resizing(img) 162 | # img.show() 163 | save_root = os.path.join(args.small_path, image_id + ".jpg") 164 | img.save(save_root, quality=95) 165 | 166 | print(" all small images are saved to {}".format(args.small_path)) 167 | 168 | 169 | if __name__ == "__main__": 170 | args = parse_args() 171 | convert(args) 172 | --------------------------------------------------------------------------------