├── data ├── __init__.py ├── __pycache__ │ ├── cifar.cpython-36.pyc │ ├── mnist.cpython-36.pyc │ ├── utils.cpython-36.pyc │ ├── __init__.cpython-36.pyc │ └── datasets.cpython-36.pyc ├── datasets.py ├── utils.py └── mnist.py ├── results └── __init__.py ├── phase2 ├── results │ └── __init__.py ├── samplers │ ├── __init__.py │ └── stratified_sampler.py ├── .DS_Store ├── indices.npy ├── labels.npy ├── confs │ ├── .DS_Store │ ├── resnet34_ins_0.2.yaml │ ├── resnet34_ins_0.4.yaml │ └── resnet34_ins_0.6.yaml ├── warmup_scheduler │ ├── __init__.py │ ├── run.py │ └── scheduler.py ├── pretrainedmodels │ ├── .DS_Store │ ├── version.py │ ├── datasets │ │ ├── __init__.py │ │ ├── utils.py │ │ └── voc.py │ ├── models │ │ ├── resnext_features │ │ │ └── __init__.py │ │ ├── utils.py │ │ ├── __init__.py │ │ ├── wideresnet.py │ │ ├── resnext.py │ │ ├── vggm.py │ │ ├── cafferesnet.py │ │ ├── fbresnet.py │ │ ├── xception.py │ │ ├── inceptionv4.py │ │ └── inceptionresnetv2.py │ ├── __init__.py │ └── utils.py ├── .vscode │ ├── settings.json │ └── launch.json ├── requirements.txt ├── common.py ├── get_noise_preds.py ├── networks │ ├── __init__.py │ ├── wideresnet.py │ ├── preact_resnet.py │ └── resnet.py ├── .gitignore ├── metrics.py ├── augmentations.py ├── utils.py ├── data.py ├── LICENSE ├── phase2.py └── noisy_cifar.py ├── .DS_Store ├── models ├── __init__.py ├── __pycache__ │ ├── resnet.cpython-36.pyc │ ├── __init__.cpython-36.pyc │ └── nine_layer_cnn.cpython-36.pyc ├── nine_layer_cnn.py └── resnet.py ├── .gitignore ├── README.md ├── loss.py └── phase1.py /data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /results/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /phase2/results/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /phase2/samplers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/.DS_Store -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | from .resnet import * 2 | from .nine_layer_cnn import * -------------------------------------------------------------------------------- /phase2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/phase2/.DS_Store -------------------------------------------------------------------------------- /phase2/indices.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/phase2/indices.npy -------------------------------------------------------------------------------- /phase2/labels.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/phase2/labels.npy -------------------------------------------------------------------------------- /phase2/confs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/phase2/confs/.DS_Store -------------------------------------------------------------------------------- /phase2/warmup_scheduler/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from warmup_scheduler.scheduler import GradualWarmupScheduler 3 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/phase2/pretrainedmodels/.DS_Store -------------------------------------------------------------------------------- /data/__pycache__/cifar.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/data/__pycache__/cifar.cpython-36.pyc -------------------------------------------------------------------------------- /data/__pycache__/mnist.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/data/__pycache__/mnist.cpython-36.pyc -------------------------------------------------------------------------------- /data/__pycache__/utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/data/__pycache__/utils.cpython-36.pyc -------------------------------------------------------------------------------- /phase2/pretrainedmodels/version.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | __version__ = '0.7.4' 3 | -------------------------------------------------------------------------------- /data/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/data/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /data/__pycache__/datasets.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/data/__pycache__/datasets.cpython-36.pyc -------------------------------------------------------------------------------- /models/__pycache__/resnet.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/models/__pycache__/resnet.cpython-36.pyc -------------------------------------------------------------------------------- /models/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/models/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /models/__pycache__/nine_layer_cnn.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haochenglouis/cores/HEAD/models/__pycache__/nine_layer_cnn.cpython-36.pyc -------------------------------------------------------------------------------- /phase2/pretrainedmodels/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | from .voc import Voc2007Classification -------------------------------------------------------------------------------- /phase2/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/raid/home/public/anaconda3/bin/python", 3 | "python.linting.pylintEnabled": true, 4 | "python.linting.enabled": true, 5 | "python.linting.flake8Enabled": false 6 | } -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/resnext_features/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | from .resnext101_32x4d_features import resnext101_32x4d_features 3 | from .resnext101_64x4d_features import resnext101_64x4d_features -------------------------------------------------------------------------------- /phase2/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/wbaek/theconf 2 | git+https://github.com/ildoonet/pytorch-gradual-warmup-lr.git@v0.2 3 | git+https://github.com/ildoonet/pystopwatch2.git 4 | pretrainedmodels 5 | tqdm 6 | tensorboardx 7 | sklearn 8 | matplotlib 9 | psutil 10 | requests -------------------------------------------------------------------------------- /phase2/warmup_scheduler/run.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from warmup_scheduler import GradualWarmupScheduler 4 | 5 | 6 | if __name__ == '__main__': 7 | v = torch.zeros(10) 8 | optim = torch.optim.SGD([v], lr=0.01) 9 | scheduler = GradualWarmupScheduler(optim, multiplier=8, total_epoch=10) 10 | 11 | for epoch in range(1, 20): 12 | scheduler.step(epoch) 13 | 14 | print(epoch, optim.param_groups[0]['lr']) 15 | -------------------------------------------------------------------------------- /phase2/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: 当前文件", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}", 12 | "console": "integratedTerminal" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /phase2/common.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | formatter = logging.Formatter('[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s') 4 | 5 | 6 | def get_logger(name, level=logging.DEBUG): 7 | logger = logging.getLogger(name) 8 | logger.handlers.clear() 9 | logger.setLevel(level) 10 | ch = logging.StreamHandler() 11 | ch.setLevel(level) 12 | ch.setFormatter(formatter) 13 | logger.addHandler(ch) 14 | return logger 15 | 16 | 17 | def add_filehandler(logger, filepath): 18 | fh = logging.FileHandler(filepath) 19 | fh.setLevel(logging.DEBUG) 20 | fh.setFormatter(formatter) 21 | logger.addHandler(fh) 22 | -------------------------------------------------------------------------------- /phase2/confs/resnet34_ins_0.2.yaml: -------------------------------------------------------------------------------- 1 | model: 2 | type: resnet34 3 | dataset: cifar10 4 | aug: autoaug_cifar10 # autoaug_extend 5 | cutout: 16 6 | batch: 320 7 | batch_unsup: 80 8 | ratio_unsup: 0.2 9 | ratio_mode: 'constant' 10 | epoch: 1600 11 | lr: 0.001 12 | lr_schedule: 13 | type: 'cosine' 14 | warmup: 15 | multiplier: 300 16 | epoch: 120 17 | optimizer: 18 | type: sgd 19 | nesterov: True 20 | decay: 0.0005 21 | 22 | random_state: 0 23 | train_labels: '../results/cifar10/resnet/coresinstance0.2train_noisy_labels.npy' 24 | unsup_idx: '../results/cifar10/resnet/coresinstance0.2_noise_pred.npy' 25 | pretrain: '' 26 | 27 | tqdm_disable: False 28 | -------------------------------------------------------------------------------- /phase2/confs/resnet34_ins_0.4.yaml: -------------------------------------------------------------------------------- 1 | model: 2 | type: resnet34 3 | dataset: cifar10 4 | aug: autoaug_cifar10 # autoaug_extend 5 | cutout: 16 6 | batch: 320 7 | batch_unsup: 160 8 | ratio_unsup: 0.4 9 | ratio_mode: 'constant' 10 | epoch: 1600 11 | lr: 0.001 12 | lr_schedule: 13 | type: 'cosine' 14 | warmup: 15 | multiplier: 300 16 | epoch: 120 17 | optimizer: 18 | type: sgd 19 | nesterov: True 20 | decay: 0.0005 21 | 22 | random_state: 0 23 | train_labels: '../results/cifar10/resnet/coresinstance0.4train_noisy_labels.npy' 24 | unsup_idx: '../results/cifar10/resnet/coresinstance0.4_noise_pred.npy' 25 | pretrain: '' 26 | 27 | tqdm_disable: False 28 | -------------------------------------------------------------------------------- /phase2/confs/resnet34_ins_0.6.yaml: -------------------------------------------------------------------------------- 1 | model: 2 | type: resnet34 3 | dataset: cifar10 4 | aug: autoaug_cifar10 # autoaug_extend 5 | cutout: 16 6 | batch: 320 7 | batch_unsup: 240 8 | ratio_unsup: 0.9 9 | ratio_mode: 'constant' 10 | epoch: 1600 11 | lr: 0.001 12 | lr_schedule: 13 | type: 'cosine' 14 | warmup: 15 | multiplier: 300 16 | epoch: 120 17 | optimizer: 18 | type: sgd 19 | nesterov: True 20 | decay: 0.0005 21 | 22 | random_state: 0 23 | train_labels: '../results/cifar10/resnet/coresinstance0.6train_noisy_labels.npy' 24 | unsup_idx: '../results/cifar10/resnet/coresinstance0.6_noise_pred.npy' 25 | pretrain: '' 26 | 27 | tqdm_disable: False 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | results/cifar10/resnet/crispsymmetric0.6.txt 2 | results/cifar10/resnet/crispsymmetric0.6best.pth.tar 3 | results/cifar10/resnet/crispsymmetric0.6last_noise_pred.npy 4 | results/cifar10/resnet/crispsymmetric0.6loss_all.npy 5 | results/cifar10/resnet/crispsymmetric0.6loss_div_all.npy 6 | __pycache__/loss.cpython-38.pyc 7 | data/__pycache__/__init__.cpython-38.pyc 8 | data/__pycache__/cifar.cpython-38.pyc 9 | data/__pycache__/datasets.cpython-38.pyc 10 | data/__pycache__/mnist.cpython-38.pyc 11 | data/__pycache__/utils.cpython-38.pyc 12 | models/__pycache__/__init__.cpython-38.pyc 13 | models/__pycache__/nine_layer_cnn.cpython-38.pyc 14 | models/__pycache__/resnet.cpython-38.pyc 15 | -------------------------------------------------------------------------------- /phase2/get_noise_preds.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | noise='symmetric' 3 | nr=0.2 4 | alpha=-4 5 | 6 | save_dir = '../results/cifar10/resnet' 7 | loss=np.load('../results/cifar10/resnet/uspl{}{}loss_div_all.npy'.format(noise,nr)) 8 | results='../results/cifar10/resnet/uspl{}{}.txt'.format(noise,nr) 9 | 10 | lines = open(results, 'r').readlines()[1:] 11 | best = 0. 12 | best_epoch = -1 13 | for line in lines: 14 | epoch, _, testacc=line.strip().split() 15 | testacc = float(testacc) 16 | if testacc > best: 17 | best=testacc 18 | best_epoch = int(epoch[:-1]) 19 | best_epoch = 21 20 | print('best_epoch ', best_epoch, best) 21 | 22 | lbest = loss[:,best_epoch] 23 | llast = loss[:,-1] 24 | 25 | idx_best = np.where(lbest>alpha)[0] 26 | print('best idx:', idx_best.shape) 27 | 28 | idx_last = np.where(llast>alpha)[0] 29 | print('last idx:', idx_last.shape) 30 | 31 | np.save(save_dir+'/usplpeer{}{}best_noise_pred.npy'.format(noise, nr), idx_best) 32 | np.save(save_dir+'/usplpeer{}{}last_noise_pred.npy'.format(noise, nr), idx_last) 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /phase2/networks/__init__.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from pretrainedmodels import models 3 | 4 | from torch import nn 5 | from torch.nn import DataParallel 6 | import torch.backends.cudnn as cudnn 7 | 8 | from networks.wideresnet import WideResNet 9 | from .resnet import ResNet34 10 | from .preact_resnet import PreActResNet18 11 | 12 | import os 13 | 14 | def get_model(conf, num_class=10, data_parallel=True, devices=None): #None means using all devices 15 | name = conf['type'] 16 | 17 | if name == 'wresnet40_2': 18 | model = WideResNet(40, 2, dropout_rate=0.0, num_classes=num_class) 19 | elif name == 'wresnet28_2': 20 | model = WideResNet(28, 2, dropout_rate=0.0, num_classes=num_class) 21 | elif name == 'wresnet28_10': 22 | model = WideResNet(28, 10, dropout_rate=0.0, num_classes=num_class) 23 | elif name == 'resnet34': 24 | model = ResNet34(num_class) 25 | elif name == 'preres18': 26 | model = PreActResNet18(num_class) 27 | else: 28 | raise NameError('no model named, %s' % name) 29 | 30 | if data_parallel: 31 | print('DEBUG: torch device count', torch.cuda.device_count()) 32 | model = model.cuda() 33 | model = DataParallel(model, device_ids=devices) 34 | else: 35 | import horovod.torch as hvd 36 | device = torch.device('cuda', hvd.local_rank()) 37 | model = model.to(device) 38 | cudnn.benchmark = True 39 | return model 40 | 41 | 42 | def num_class(dataset): 43 | return { 44 | 'cifar10': 10, 45 | 'reduced_cifar10': 10, 46 | 'cifar100': 100, 47 | 'imagenet': 1000, 48 | 'reduced_imagenet': 120, 49 | }[dataset] 50 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | from .fbresnet import pretrained_settings as fbresnet_settings 3 | from .bninception import pretrained_settings as bninception_settings 4 | from .resnext import pretrained_settings as resnext_settings 5 | from .inceptionv4 import pretrained_settings as inceptionv4_settings 6 | from .inceptionresnetv2 import pretrained_settings as inceptionresnetv2_settings 7 | from .torchvision_models import pretrained_settings as torchvision_models_settings 8 | from .nasnet_mobile import pretrained_settings as nasnet_mobile_settings 9 | from .nasnet import pretrained_settings as nasnet_settings 10 | from .dpn import pretrained_settings as dpn_settings 11 | from .xception import pretrained_settings as xception_settings 12 | from .senet import pretrained_settings as senet_settings 13 | from .cafferesnet import pretrained_settings as cafferesnet_settings 14 | from .pnasnet import pretrained_settings as pnasnet_settings 15 | from .polynet import pretrained_settings as polynet_settings 16 | 17 | all_settings = [ 18 | fbresnet_settings, 19 | bninception_settings, 20 | resnext_settings, 21 | inceptionv4_settings, 22 | inceptionresnetv2_settings, 23 | torchvision_models_settings, 24 | nasnet_mobile_settings, 25 | nasnet_settings, 26 | dpn_settings, 27 | xception_settings, 28 | senet_settings, 29 | cafferesnet_settings, 30 | pnasnet_settings, 31 | polynet_settings 32 | ] 33 | 34 | model_names = [] 35 | pretrained_settings = {} 36 | for settings in all_settings: 37 | for model_name, model_settings in settings.items(): 38 | pretrained_settings[model_name] = model_settings 39 | model_names.append(model_name) 40 | -------------------------------------------------------------------------------- /phase2/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning with Instance-Dependent Label Noise: A Sample Sieve Approach 2 | This code is a PyTorch implementation of our paper "[Learning with Instance-Dependent Label Noise: A Sample Sieve Approach](https://arxiv.org/abs/2010.02347)" accepted by ICLR2021. 3 | 4 | The code is run on the Tesla V-100. 5 | ## Prerequisites 6 | Python 3.6.9 7 | 8 | PyTorch 1.2.0 9 | 10 | Torchvision 0.5.0 11 | 12 | 13 | ## Steps on Runing CORES on CIFAR 10 14 | ### Step 1: 15 | 16 | Download the datset from **http://www.cs.toronto.edu/~kriz/cifar.html** Put the dataset on **data/** 17 | 18 | Install theconf by **pip install git+https://github.com/wbaek/theconf.git** 19 | 20 | 21 | ### Step 2: 22 | 23 | Run CORES (Phase 1: Sample Sieve) on CIFAR-10 with instance 0.6 noise: 24 | 25 | ``` 26 | CUDA_VISIBLE_DEVICES=0 python phase1.py --loss cores --dataset cifar10 --model resnet --noise_type instance --noise_rate 0.6 27 | ``` 28 | ### Step 3: 29 | Run CORES (Phase 2: Consistency Training) on the CIFAR-10 with instance 0.6 noise: 30 | 31 | ``` 32 | cd phase2 33 | CUDA_VISIBLE_DEVICES=0,1 python phase2.py -c confs/resnet34_ins_0.6.yaml --unsupervised 34 | ``` 35 | **Both Phase 1 and Phase 2 do not need pre-trained model.** 36 | 37 | 38 | ## Citation 39 | 40 | If you find this code useful, please cite the following paper: 41 | 42 | ``` 43 | @article{cheng2020learning, 44 | title={Learning with Instance-Dependent Label Noise: A Sample Sieve Approach}, 45 | author={Cheng, Hao and Zhu, Zhaowei and Li, Xingyu and Gong, Yifei and Sun, Xing and Liu, Yang}, 46 | journal={arXiv preprint arXiv:2010.02347}, 47 | year={2020} 48 | } 49 | ``` 50 | 51 | 52 | ## References 53 | 54 | The code of Phase 2 is based on **https://github.com/ildoonet/unsupervised-data-augmentation** 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | from .fbresnet import fbresnet152 3 | 4 | from .cafferesnet import cafferesnet101 5 | 6 | from .bninception import bninception 7 | 8 | from .resnext import resnext101_32x4d 9 | from .resnext import resnext101_64x4d 10 | 11 | from .inceptionv4 import inceptionv4 12 | 13 | from .inceptionresnetv2 import inceptionresnetv2 14 | 15 | from .nasnet import nasnetalarge 16 | 17 | from .nasnet_mobile import nasnetamobile 18 | 19 | from .torchvision_models import alexnet 20 | from .torchvision_models import densenet121 21 | from .torchvision_models import densenet169 22 | from .torchvision_models import densenet201 23 | from .torchvision_models import densenet161 24 | from .torchvision_models import resnet18 25 | from .torchvision_models import resnet34 26 | from .torchvision_models import resnet50 27 | from .torchvision_models import resnet101 28 | from .torchvision_models import resnet152 29 | from .torchvision_models import inceptionv3 30 | from .torchvision_models import squeezenet1_0 31 | from .torchvision_models import squeezenet1_1 32 | from .torchvision_models import vgg11 33 | from .torchvision_models import vgg11_bn 34 | from .torchvision_models import vgg13 35 | from .torchvision_models import vgg13_bn 36 | from .torchvision_models import vgg16 37 | from .torchvision_models import vgg16_bn 38 | from .torchvision_models import vgg19_bn 39 | from .torchvision_models import vgg19 40 | 41 | from .dpn import dpn68 42 | from .dpn import dpn68b 43 | from .dpn import dpn92 44 | from .dpn import dpn98 45 | from .dpn import dpn131 46 | from .dpn import dpn107 47 | 48 | from .xception import xception 49 | 50 | from .senet import senet154 51 | from .senet import se_resnet50 52 | from .senet import se_resnet101 53 | from .senet import se_resnet152 54 | from .senet import se_resnext50_32x4d 55 | from .senet import se_resnext101_32x4d 56 | 57 | from .pnasnet import pnasnet5large 58 | from .polynet import polynet 59 | -------------------------------------------------------------------------------- /phase2/samplers/stratified_sampler.py: -------------------------------------------------------------------------------- 1 | import random 2 | from collections import defaultdict 3 | 4 | from torch.utils.data import Sampler 5 | 6 | 7 | class StratifiedSampler(Sampler): 8 | def __init__(self, labels): 9 | self.idx_by_lb = defaultdict(list) 10 | for idx, lb in enumerate(labels): 11 | self.idx_by_lb[lb].append(idx) 12 | 13 | self.size = len(labels) 14 | 15 | def __len__(self): 16 | return self.size 17 | 18 | def __iter__(self): 19 | songs_list = [] 20 | artists_list = [] 21 | for lb, v in self.idx_by_lb.items(): 22 | for idx in v: 23 | songs_list.append(idx) 24 | artists_list.append(lb) 25 | 26 | shuffled = spotifyShuffle(songs_list, artists_list) 27 | return iter(shuffled) 28 | 29 | 30 | def fisherYatesShuffle(arr): 31 | """ 32 | https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle 33 | for i from n−1 downto 1 do 34 | j ← random integer such that 0 ≤ j ≤ i 35 | exchange a[j] and a[i] 36 | """ 37 | for i in range(len(arr)-1, 0, -1): 38 | j = random.randint(0, i) 39 | arr[i], arr[j] = arr[j], arr[i] 40 | return arr 41 | 42 | 43 | def spotifyShuffle(songs_list, artists_list): 44 | artist2songs = defaultdict(list) 45 | for artist, song in zip(artists_list, songs_list): 46 | artist2songs[artist].append(song) 47 | songList = [] 48 | songsLocs = [] 49 | for artist, songs in artist2songs.items(): 50 | songs = fisherYatesShuffle(songs) 51 | songList += songs 52 | songsLocs += get_locs(len(songs)) 53 | return [songList[idx] for idx in argsort(songsLocs)] 54 | 55 | 56 | def argsort(seq): 57 | return [i for i, j in sorted(enumerate(seq), key=lambda x:x[1])] 58 | 59 | 60 | def get_locs(n): 61 | percent = 1. / n 62 | locs = [percent * random.random()] 63 | last = locs[0] 64 | for i in range(n - 1): 65 | value = last + percent * random.uniform(0.8, 1.2) # 25% : 20~30% = 1 : 0.8x~1.2x 66 | locs.append(value) 67 | last = value 68 | return locs 69 | -------------------------------------------------------------------------------- /loss.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torch.autograd import Variable 5 | import numpy as np 6 | import random 7 | import math 8 | # Loss functions 9 | 10 | 11 | def loss_cross_entropy(epoch, y, t,class_list, ind, noise_or_not,loss_all,loss_div_all): 12 | ##Record loss and loss_div for further analysis 13 | loss = F.cross_entropy(y, t, reduce = False) 14 | loss_numpy = loss.data.cpu().numpy() 15 | num_batch = len(loss_numpy) 16 | loss_all[ind,epoch] = loss_numpy 17 | return torch.sum(loss)/num_batch 18 | 19 | 20 | 21 | 22 | 23 | def loss_cores(epoch, y, t,class_list, ind, noise_or_not,loss_all,loss_div_all, noise_prior = None): 24 | beta = f_beta(epoch) 25 | # if epoch == 1: 26 | # print(f'current beta is {beta}') 27 | loss = F.cross_entropy(y, t, reduce = False) 28 | loss_numpy = loss.data.cpu().numpy() 29 | num_batch = len(loss_numpy) 30 | loss_v = np.zeros(num_batch) 31 | loss_div_numpy = float(np.array(0)) 32 | loss_ = -torch.log(F.softmax(y) + 1e-8) 33 | # sel metric 34 | loss_sel = loss - torch.mean(loss_,1) 35 | if noise_prior is None: 36 | loss = loss - beta*torch.mean(loss_,1) 37 | else: 38 | loss = loss - beta*torch.sum(torch.mul(noise_prior, loss_),1) 39 | 40 | loss_div_numpy = loss_sel.data.cpu().numpy() 41 | loss_all[ind,epoch] = loss_numpy 42 | loss_div_all[ind,epoch] = loss_div_numpy 43 | for i in range(len(loss_numpy)): 44 | if epoch <=30: 45 | loss_v[i] = 1.0 46 | elif loss_div_numpy[i] <= 0: 47 | loss_v[i] = 1.0 48 | loss_v = loss_v.astype(np.float32) 49 | loss_v_var = Variable(torch.from_numpy(loss_v)).cuda() 50 | loss_ = loss_v_var * loss 51 | if sum(loss_v) == 0.0: 52 | return torch.mean(loss_)/100000000 53 | else: 54 | return torch.sum(loss_)/sum(loss_v), loss_v.astype(int) 55 | 56 | def f_beta(epoch): 57 | beta1 = np.linspace(0.0, 0.0, num=10) 58 | beta2 = np.linspace(0.0, 2, num=30) 59 | beta3 = np.linspace(2, 2, num=60) 60 | 61 | beta = np.concatenate((beta1,beta2,beta3),axis=0) 62 | return beta[epoch] 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /phase2/metrics.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | import torch 4 | from collections import defaultdict 5 | 6 | from torch import nn 7 | 8 | 9 | def accuracy(output, target, topk=(1,)): 10 | """Computes the precision@k for the specified values of k""" 11 | maxk = max(topk) 12 | batch_size = target.size(0) 13 | 14 | _, pred = output.topk(maxk, 1, True, True) 15 | pred = pred.t() 16 | correct = pred.eq(target.view(1, -1).expand_as(pred)) 17 | 18 | res = [] 19 | for k in topk: 20 | correct_k = correct[:k].view(-1).float().sum(0) 21 | res.append(correct_k.mul_(1. / batch_size)) 22 | return res 23 | 24 | 25 | def cross_entropy_smooth(input, target, size_average=True, label_smoothing=0.1): 26 | y = torch.eye(10).cuda() 27 | lb_oh = y[target] 28 | 29 | target = lb_oh * (1 - label_smoothing) + 0.5 * label_smoothing 30 | 31 | logsoftmax = nn.LogSoftmax() 32 | if size_average: 33 | return torch.mean(torch.sum(-target * logsoftmax(input), dim=1)) 34 | else: 35 | return torch.sum(torch.sum(-target * logsoftmax(input), dim=1)) 36 | 37 | 38 | class Accumulator: 39 | def __init__(self): 40 | self.metrics = defaultdict(lambda: 0.) 41 | 42 | def add(self, key, value): 43 | self.metrics[key] += value 44 | 45 | def add_dict(self, dict): 46 | for key, value in dict.items(): 47 | self.add(key, value) 48 | 49 | def __getitem__(self, item): 50 | return self.metrics[item] 51 | 52 | def __setitem__(self, key, value): 53 | self.metrics[key] = value 54 | 55 | def get_dict(self): 56 | return copy.deepcopy(dict(self.metrics)) 57 | 58 | def items(self): 59 | return self.metrics.items() 60 | 61 | def __str__(self): 62 | return str(dict(self.metrics)) 63 | 64 | def __truediv__(self, other): 65 | newone = Accumulator() 66 | for key, value in self.items(): 67 | if isinstance(other, str): 68 | if other != key: 69 | newone[key] = value / self[other] 70 | else: 71 | newone[key] = value 72 | else: 73 | newone[key] = value / other 74 | return newone 75 | 76 | 77 | class SummaryWriterDummy: 78 | def __init__(self, logdir): 79 | pass 80 | 81 | def add_scalar(self, *args, **kwargs): 82 | pass 83 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/__init__.py: -------------------------------------------------------------------------------- 1 | from .version import __version__ 2 | 3 | from . import models 4 | from . import datasets 5 | 6 | from .models.utils import pretrained_settings 7 | from .models.utils import model_names 8 | 9 | # to support pretrainedmodels.__dict__['nasnetalarge'] 10 | # but depreciated 11 | from .models.fbresnet import fbresnet152 12 | from .models.cafferesnet import cafferesnet101 13 | from .models.bninception import bninception 14 | from .models.resnext import resnext101_32x4d 15 | from .models.resnext import resnext101_64x4d 16 | from .models.inceptionv4 import inceptionv4 17 | from .models.inceptionresnetv2 import inceptionresnetv2 18 | from .models.nasnet import nasnetalarge 19 | from .models.nasnet_mobile import nasnetamobile 20 | from .models.torchvision_models import alexnet 21 | from .models.torchvision_models import densenet121 22 | from .models.torchvision_models import densenet169 23 | from .models.torchvision_models import densenet201 24 | from .models.torchvision_models import densenet161 25 | from .models.torchvision_models import resnet18 26 | from .models.torchvision_models import resnet34 27 | from .models.torchvision_models import resnet50 28 | from .models.torchvision_models import resnet101 29 | from .models.torchvision_models import resnet152 30 | from .models.torchvision_models import inceptionv3 31 | from .models.torchvision_models import squeezenet1_0 32 | from .models.torchvision_models import squeezenet1_1 33 | from .models.torchvision_models import vgg11 34 | from .models.torchvision_models import vgg11_bn 35 | from .models.torchvision_models import vgg13 36 | from .models.torchvision_models import vgg13_bn 37 | from .models.torchvision_models import vgg16 38 | from .models.torchvision_models import vgg16_bn 39 | from .models.torchvision_models import vgg19_bn 40 | from .models.torchvision_models import vgg19 41 | from .models.dpn import dpn68 42 | from .models.dpn import dpn68b 43 | from .models.dpn import dpn92 44 | from .models.dpn import dpn98 45 | from .models.dpn import dpn131 46 | from .models.dpn import dpn107 47 | from .models.xception import xception 48 | from .models.senet import senet154 49 | from .models.senet import se_resnet50 50 | from .models.senet import se_resnet101 51 | from .models.senet import se_resnet152 52 | from .models.senet import se_resnext50_32x4d 53 | from .models.senet import se_resnext101_32x4d 54 | from .models.pnasnet import pnasnet5large 55 | from .models.polynet import polynet 56 | -------------------------------------------------------------------------------- /data/datasets.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torchvision.transforms as transforms 3 | from .cifar import CIFAR10, CIFAR100 4 | 5 | 6 | 7 | train_cifar10_transform = transforms.Compose([ 8 | transforms.RandomCrop(32, padding=4), 9 | transforms.RandomHorizontalFlip(), 10 | transforms.ToTensor(), 11 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 12 | ]) 13 | 14 | test_cifar10_transform = transforms.Compose([ 15 | transforms.ToTensor(), 16 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 17 | ]) 18 | train_cifar100_transform = transforms.Compose([ 19 | transforms.RandomCrop(32, padding=4), 20 | transforms.RandomHorizontalFlip(), 21 | transforms.ToTensor(), 22 | transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761)), 23 | ]) 24 | 25 | test_cifar100_transform = transforms.Compose([ 26 | transforms.ToTensor(), 27 | transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761)), 28 | ]) 29 | def input_dataset(dataset, noise_type, noise_ratio): 30 | if dataset == 'cifar10': 31 | train_dataset = CIFAR10(root='./data/', 32 | download=False, 33 | train=True, 34 | transform = train_cifar10_transform, 35 | noise_type=noise_type, 36 | noise_rate=noise_ratio 37 | ) 38 | test_dataset = CIFAR10(root='./data/', 39 | download=False, 40 | train=False, 41 | transform = test_cifar10_transform, 42 | noise_type=noise_type, 43 | noise_rate=noise_ratio 44 | ) 45 | num_classes = 10 46 | num_training_samples = 50000 47 | elif dataset == 'cifar100': 48 | train_dataset = CIFAR100(root='./data/', 49 | download=True, 50 | train=True, 51 | transform=train_cifar100_transform, 52 | noise_type=noise_type, 53 | noise_rate=noise_ratio 54 | ) 55 | test_dataset = CIFAR100(root='./data/', 56 | download=True, 57 | train=False, 58 | transform=test_cifar100_transform, 59 | noise_type=noise_type, 60 | noise_rate=noise_ratio 61 | ) 62 | num_classes = 100 63 | num_training_samples = 50000 64 | return train_dataset, test_dataset, num_classes, num_training_samples 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /models/nine_layer_cnn.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.init as init 5 | import torch.nn.functional as F 6 | import torch.optim as optim 7 | 8 | def call_bn(bn, x): 9 | return bn(x) 10 | 11 | class CNN(nn.Module): 12 | def __init__(self, input_channel=3, n_outputs=10, dropout_rate=0.25, top_bn=False): 13 | self.dropout_rate = dropout_rate 14 | self.top_bn = top_bn 15 | super(CNN, self).__init__() 16 | self.c1=nn.Conv2d(input_channel,128,kernel_size=3,stride=1, padding=1) 17 | self.c2=nn.Conv2d(128,128,kernel_size=3,stride=1, padding=1) 18 | self.c3=nn.Conv2d(128,128,kernel_size=3,stride=1, padding=1) 19 | self.c4=nn.Conv2d(128,256,kernel_size=3,stride=1, padding=1) 20 | self.c5=nn.Conv2d(256,256,kernel_size=3,stride=1, padding=1) 21 | self.c6=nn.Conv2d(256,256,kernel_size=3,stride=1, padding=1) 22 | self.c7=nn.Conv2d(256,512,kernel_size=3,stride=1, padding=0) 23 | self.c8=nn.Conv2d(512,256,kernel_size=3,stride=1, padding=0) 24 | self.c9=nn.Conv2d(256,128,kernel_size=3,stride=1, padding=0) 25 | self.l_c1=nn.Linear(128,n_outputs) 26 | self.bn1=nn.BatchNorm2d(128) 27 | self.bn2=nn.BatchNorm2d(128) 28 | self.bn3=nn.BatchNorm2d(128) 29 | self.bn4=nn.BatchNorm2d(256) 30 | self.bn5=nn.BatchNorm2d(256) 31 | self.bn6=nn.BatchNorm2d(256) 32 | self.bn7=nn.BatchNorm2d(512) 33 | self.bn8=nn.BatchNorm2d(256) 34 | self.bn9=nn.BatchNorm2d(128) 35 | 36 | def forward(self, x,): 37 | h=x 38 | h=self.c1(h) 39 | h=F.leaky_relu(call_bn(self.bn1, h), negative_slope=0.01) 40 | h=self.c2(h) 41 | h=F.leaky_relu(call_bn(self.bn2, h), negative_slope=0.01) 42 | h=self.c3(h) 43 | h=F.leaky_relu(call_bn(self.bn3, h), negative_slope=0.01) 44 | h=F.max_pool2d(h, kernel_size=2, stride=2) 45 | h=F.dropout2d(h, p=self.dropout_rate) 46 | 47 | h=self.c4(h) 48 | h=F.leaky_relu(call_bn(self.bn4, h), negative_slope=0.01) 49 | h=self.c5(h) 50 | h=F.leaky_relu(call_bn(self.bn5, h), negative_slope=0.01) 51 | h=self.c6(h) 52 | h=F.leaky_relu(call_bn(self.bn6, h), negative_slope=0.01) 53 | h=F.max_pool2d(h, kernel_size=2, stride=2) 54 | h=F.dropout2d(h, p=self.dropout_rate) 55 | 56 | h=self.c7(h) 57 | h=F.leaky_relu(call_bn(self.bn7, h), negative_slope=0.01) 58 | h=self.c8(h) 59 | h=F.leaky_relu(call_bn(self.bn8, h), negative_slope=0.01) 60 | h=self.c9(h) 61 | h=F.leaky_relu(call_bn(self.bn9, h), negative_slope=0.01) 62 | h=F.avg_pool2d(h, kernel_size=h.data.shape[2]) 63 | 64 | h = h.view(h.size(0), h.size(1)) 65 | logit=self.l_c1(h) 66 | if self.top_bn: 67 | logit=call_bn(self.bn_c1, logit) 68 | return logit 69 | 70 | 71 | -------------------------------------------------------------------------------- /phase2/warmup_scheduler/scheduler.py: -------------------------------------------------------------------------------- 1 | from torch.optim.lr_scheduler import _LRScheduler 2 | from torch.optim.lr_scheduler import ReduceLROnPlateau 3 | 4 | 5 | class GradualWarmupScheduler(_LRScheduler): 6 | """ Gradually warm-up(increasing) learning rate in optimizer. 7 | Proposed in 'Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour'. 8 | 9 | Args: 10 | optimizer (Optimizer): Wrapped optimizer. 11 | multiplier: target learning rate = base lr * multiplier 12 | total_epoch: target learning rate is reached at total_epoch, gradually 13 | after_scheduler: after target_epoch, use this scheduler(eg. ReduceLROnPlateau) 14 | """ 15 | 16 | def __init__(self, optimizer, multiplier, total_epoch, after_scheduler=None): 17 | self.multiplier = multiplier 18 | if self.multiplier <= 1.: 19 | raise ValueError('multiplier should be greater than 1.') 20 | self.total_epoch = total_epoch 21 | self.after_scheduler = after_scheduler 22 | self.finished = False 23 | super().__init__(optimizer) 24 | 25 | def get_lr(self): 26 | if self.last_epoch > self.total_epoch: 27 | if self.after_scheduler: 28 | if not self.finished: 29 | self.after_scheduler.base_lrs = [base_lr * self.multiplier for base_lr in self.base_lrs] 30 | self.finished = True 31 | return self.after_scheduler.get_lr() 32 | return [base_lr * self.multiplier for base_lr in self.base_lrs] 33 | 34 | return [base_lr * ((self.multiplier - 1.) * self.last_epoch / self.total_epoch + 1.) for base_lr in self.base_lrs] 35 | 36 | def step_ReduceLROnPlateau(self, metrics, epoch=None): 37 | if epoch is None: 38 | epoch = self.last_epoch + 1 39 | self.last_epoch = epoch if epoch != 0 else 1 # ReduceLROnPlateau is called at the end of epoch, whereas others are called at beginning 40 | if self.last_epoch <= self.total_epoch: 41 | warmup_lr = [base_lr * ((self.multiplier - 1.) * self.last_epoch / self.total_epoch + 1.) for base_lr in self.base_lrs] 42 | for param_group, lr in zip(self.optimizer.param_groups, warmup_lr): 43 | param_group['lr'] = lr 44 | else: 45 | if epoch is None: 46 | self.after_scheduler.step(metrics, None) 47 | else: 48 | self.after_scheduler.step(metrics, epoch - self.total_epoch) 49 | 50 | def step(self, epoch=None, metrics=None): 51 | if type(self.after_scheduler) != ReduceLROnPlateau: 52 | if self.finished and self.after_scheduler: 53 | if epoch is None: 54 | self.after_scheduler.step(None) 55 | else: 56 | self.after_scheduler.step(epoch - self.total_epoch) 57 | else: 58 | return super(GradualWarmupScheduler, self).step(epoch) 59 | else: 60 | self.step_ReduceLROnPlateau(metrics, epoch) 61 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/wideresnet.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import os 3 | from os.path import expanduser 4 | import hickle as hkl 5 | import torch 6 | import torch.nn.functional as F 7 | from torch.autograd import Variable 8 | 9 | __all__ = ['wideresnet50'] 10 | 11 | model_urls = { 12 | 'wideresnet152': 'https://s3.amazonaws.com/pytorch/h5models/wide-resnet-50-2-export.hkl' 13 | } 14 | 15 | def define_model(params): 16 | def conv2d(input, params, base, stride=1, pad=0): 17 | return F.conv2d(input, params[base + '.weight'], 18 | params[base + '.bias'], stride, pad) 19 | 20 | def group(input, params, base, stride, n): 21 | o = input 22 | for i in range(0,n): 23 | b_base = ('%s.block%d.conv') % (base, i) 24 | x = o 25 | o = conv2d(x, params, b_base + '0') 26 | o = F.relu(o) 27 | o = conv2d(o, params, b_base + '1', stride=i==0 and stride or 1, pad=1) 28 | o = F.relu(o) 29 | o = conv2d(o, params, b_base + '2') 30 | if i == 0: 31 | o += conv2d(x, params, b_base + '_dim', stride=stride) 32 | else: 33 | o += x 34 | o = F.relu(o) 35 | return o 36 | 37 | # determine network size by parameters 38 | blocks = [sum([re.match('group%d.block\d+.conv0.weight'%j, k) is not None 39 | for k in params.keys()]) for j in range(4)] 40 | 41 | def f(input, params, pooling_classif=True): 42 | o = F.conv2d(input, params['conv0.weight'], params['conv0.bias'], 2, 3) 43 | o = F.relu(o) 44 | o = F.max_pool2d(o, 3, 2, 1) 45 | o_g0 = group(o, params, 'group0', 1, blocks[0]) 46 | o_g1 = group(o_g0, params, 'group1', 2, blocks[1]) 47 | o_g2 = group(o_g1, params, 'group2', 2, blocks[2]) 48 | o_g3 = group(o_g2, params, 'group3', 2, blocks[3]) 49 | if pooling_classif: 50 | o = F.avg_pool2d(o_g3, 7, 1, 0) 51 | o = o.view(o.size(0), -1) 52 | o = F.linear(o, params['fc.weight'], params['fc.bias']) 53 | return o 54 | 55 | return f 56 | 57 | 58 | class WideResNet(nn.Module): 59 | 60 | def __init__(self, pooling): 61 | super(WideResNet, self).__init__() 62 | self.pooling = pooling 63 | self.params = params 64 | 65 | def forward(self, x): 66 | x = f(x, self.params, self.pooling) 67 | return x 68 | 69 | 70 | def wideresnet50(pooling): 71 | dir_models = os.path.join(expanduser("~"), '.torch/wideresnet') 72 | path_hkl = os.path.join(dir_models, 'wideresnet50.hkl') 73 | if os.path.isfile(path_hkl): 74 | params = hkl.load(path_hkl) 75 | # convert numpy arrays to torch Variables 76 | for k,v in sorted(params.items()): 77 | print(k, v.shape) 78 | params[k] = Variable(torch.from_numpy(v), requires_grad=True) 79 | else: 80 | os.system('mkdir -p ' + dir_models) 81 | os.system('wget {} -O {}'.format(model_urls['wideresnet50'], path_hkl)) 82 | f = define_model(params) 83 | model = WideResNet(pooling) 84 | return model 85 | 86 | 87 | -------------------------------------------------------------------------------- /phase2/networks/wideresnet.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import torch.nn.init as init 3 | import torch.nn.functional as F 4 | import numpy as np 5 | 6 | 7 | bn_momentum = 0.9 8 | 9 | 10 | def conv3x3(in_planes, out_planes, stride=1): 11 | return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=True) 12 | 13 | 14 | def conv_init(m): 15 | classname = m.__class__.__name__ 16 | if classname.find('Conv') != -1: 17 | init.xavier_uniform_(m.weight, gain=np.sqrt(2)) 18 | init.constant_(m.bias, 0) 19 | elif classname.find('BatchNorm') != -1: 20 | init.constant_(m.weight, 1) 21 | init.constant_(m.bias, 0) 22 | 23 | 24 | class WideBasic(nn.Module): 25 | def __init__(self, in_planes, planes, dropout_rate, stride=1): 26 | super(WideBasic, self).__init__() 27 | self.bn1 = nn.BatchNorm2d(in_planes, momentum=bn_momentum) 28 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, padding=1, bias=True) 29 | self.dropout = nn.Dropout(p=dropout_rate) 30 | self.bn2 = nn.BatchNorm2d(planes, momentum=bn_momentum) 31 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=True) 32 | 33 | self.shortcut = nn.Sequential() 34 | if stride != 1 or in_planes != planes: 35 | self.shortcut = nn.Sequential( 36 | nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=True), 37 | ) 38 | 39 | def forward(self, x): 40 | out = self.dropout(self.conv1(F.relu(self.bn1(x)))) 41 | out = self.conv2(F.relu(self.bn2(out))) 42 | out += self.shortcut(x) 43 | 44 | return out 45 | 46 | 47 | class WideResNet(nn.Module): 48 | def __init__(self, depth, widen_factor, dropout_rate, num_classes): 49 | super(WideResNet, self).__init__() 50 | self.in_planes = 16 51 | 52 | assert ((depth - 4) % 6 == 0), 'Wide-resnet depth should be 6n+4' 53 | n = int((depth - 4) / 6) 54 | k = widen_factor 55 | 56 | nStages = [16, 16*k, 32*k, 64*k] 57 | 58 | self.conv1 = conv3x3(3, nStages[0]) 59 | self.layer1 = self._wide_layer(WideBasic, nStages[1], n, dropout_rate, stride=1) 60 | self.layer2 = self._wide_layer(WideBasic, nStages[2], n, dropout_rate, stride=2) 61 | self.layer3 = self._wide_layer(WideBasic, nStages[3], n, dropout_rate, stride=2) 62 | self.bn1 = nn.BatchNorm2d(nStages[3], momentum=bn_momentum) 63 | self.linear = nn.Linear(nStages[3], num_classes) 64 | 65 | # self.apply(conv_init) 66 | 67 | def _wide_layer(self, block, planes, num_blocks, dropout_rate, stride): 68 | strides = [stride] + [1]*(num_blocks-1) 69 | layers = [] 70 | 71 | for stride in strides: 72 | layers.append(block(self.in_planes, planes, dropout_rate, stride)) 73 | self.in_planes = planes 74 | 75 | return nn.Sequential(*layers) 76 | 77 | def forward(self, x): 78 | out = self.conv1(x) 79 | out = self.layer1(out) 80 | out = self.layer2(out) 81 | out = self.layer3(out) 82 | out = F.relu(self.bn1(out)) 83 | # out = F.avg_pool2d(out, 8) 84 | out = F.adaptive_avg_pool2d(out, (1, 1)) 85 | out = out.view(out.size(0), -1) 86 | out = self.linear(out) 87 | 88 | return out 89 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import math 3 | import torch 4 | import torch.nn as nn 5 | import torchvision.transforms as transforms 6 | from PIL import Image 7 | from munch import munchify 8 | 9 | class ToSpaceBGR(object): 10 | 11 | def __init__(self, is_bgr): 12 | self.is_bgr = is_bgr 13 | 14 | def __call__(self, tensor): 15 | if self.is_bgr: 16 | new_tensor = tensor.clone() 17 | new_tensor[0] = tensor[2] 18 | new_tensor[2] = tensor[0] 19 | tensor = new_tensor 20 | return tensor 21 | 22 | 23 | class ToRange255(object): 24 | 25 | def __init__(self, is_255): 26 | self.is_255 = is_255 27 | 28 | def __call__(self, tensor): 29 | if self.is_255: 30 | tensor.mul_(255) 31 | return tensor 32 | 33 | 34 | class TransformImage(object): 35 | 36 | def __init__(self, opts, scale=0.875, random_crop=False, 37 | random_hflip=False, random_vflip=False, 38 | preserve_aspect_ratio=True): 39 | if type(opts) == dict: 40 | opts = munchify(opts) 41 | self.input_size = opts.input_size 42 | self.input_space = opts.input_space 43 | self.input_range = opts.input_range 44 | self.mean = opts.mean 45 | self.std = opts.std 46 | 47 | # https://github.com/tensorflow/models/blob/master/research/inception/inception/image_processing.py#L294 48 | self.scale = scale 49 | self.random_crop = random_crop 50 | self.random_hflip = random_hflip 51 | self.random_vflip = random_vflip 52 | 53 | tfs = [] 54 | if preserve_aspect_ratio: 55 | tfs.append(transforms.Resize(int(math.floor(max(self.input_size)/self.scale)))) 56 | else: 57 | height = int(self.input_size[1] / self.scale) 58 | width = int(self.input_size[2] / self.scale) 59 | tfs.append(transforms.Resize((height, width))) 60 | 61 | if random_crop: 62 | tfs.append(transforms.RandomCrop(max(self.input_size))) 63 | else: 64 | tfs.append(transforms.CenterCrop(max(self.input_size))) 65 | 66 | if random_hflip: 67 | tfs.append(transforms.RandomHorizontalFlip()) 68 | 69 | if random_vflip: 70 | tfs.append(transforms.RandomVerticalFlip()) 71 | 72 | tfs.append(transforms.ToTensor()) 73 | tfs.append(ToSpaceBGR(self.input_space=='BGR')) 74 | tfs.append(ToRange255(max(self.input_range)==255)) 75 | tfs.append(transforms.Normalize(mean=self.mean, std=self.std)) 76 | 77 | self.tf = transforms.Compose(tfs) 78 | 79 | def __call__(self, img): 80 | tensor = self.tf(img) 81 | return tensor 82 | 83 | 84 | class LoadImage(object): 85 | 86 | def __init__(self, space='RGB'): 87 | self.space = space 88 | 89 | def __call__(self, path_img): 90 | with open(path_img, 'rb') as f: 91 | with Image.open(f) as img: 92 | img = img.convert(self.space) 93 | return img 94 | 95 | 96 | class LoadTransformImage(object): 97 | 98 | def __init__(self, model, scale=0.875): 99 | self.load = LoadImage() 100 | self.tf = TransformImage(model, scale=scale) 101 | 102 | def __call__(self, path_img): 103 | img = self.load(path_img) 104 | tensor = self.tf(img) 105 | return tensor 106 | 107 | 108 | class Identity(nn.Module): 109 | 110 | def __init__(self): 111 | super(Identity, self).__init__() 112 | 113 | def forward(self, x): 114 | return x -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/resnext.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import os 3 | import torch 4 | import torch.nn as nn 5 | import torch.utils.model_zoo as model_zoo 6 | from .resnext_features import resnext101_32x4d_features 7 | from .resnext_features import resnext101_64x4d_features 8 | 9 | __all__ = ['ResNeXt101_32x4d', 'resnext101_32x4d', 10 | 'ResNeXt101_64x4d', 'resnext101_64x4d'] 11 | 12 | pretrained_settings = { 13 | 'resnext101_32x4d': { 14 | 'imagenet': { 15 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/resnext101_32x4d-29e315fa.pth', 16 | 'input_space': 'RGB', 17 | 'input_size': [3, 224, 224], 18 | 'input_range': [0, 1], 19 | 'mean': [0.485, 0.456, 0.406], 20 | 'std': [0.229, 0.224, 0.225], 21 | 'num_classes': 1000 22 | } 23 | }, 24 | 'resnext101_64x4d': { 25 | 'imagenet': { 26 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/resnext101_64x4d-e77a0586.pth', 27 | 'input_space': 'RGB', 28 | 'input_size': [3, 224, 224], 29 | 'input_range': [0, 1], 30 | 'mean': [0.485, 0.456, 0.406], 31 | 'std': [0.229, 0.224, 0.225], 32 | 'num_classes': 1000 33 | } 34 | } 35 | } 36 | 37 | class ResNeXt101_32x4d(nn.Module): 38 | 39 | def __init__(self, num_classes=1000): 40 | super(ResNeXt101_32x4d, self).__init__() 41 | self.num_classes = num_classes 42 | self.features = resnext101_32x4d_features 43 | self.avg_pool = nn.AvgPool2d((7, 7), (1, 1)) 44 | self.last_linear = nn.Linear(2048, num_classes) 45 | 46 | def logits(self, input): 47 | x = self.avg_pool(input) 48 | x = x.view(x.size(0), -1) 49 | x = self.last_linear(x) 50 | return x 51 | 52 | def forward(self, input): 53 | x = self.features(input) 54 | x = self.logits(x) 55 | return x 56 | 57 | 58 | class ResNeXt101_64x4d(nn.Module): 59 | 60 | def __init__(self, num_classes=1000): 61 | super(ResNeXt101_64x4d, self).__init__() 62 | self.num_classes = num_classes 63 | self.features = resnext101_64x4d_features 64 | self.avg_pool = nn.AvgPool2d((7, 7), (1, 1)) 65 | self.last_linear = nn.Linear(2048, num_classes) 66 | 67 | def logits(self, input): 68 | x = self.avg_pool(input) 69 | x = x.view(x.size(0), -1) 70 | x = self.last_linear(x) 71 | return x 72 | 73 | def forward(self, input): 74 | x = self.features(input) 75 | x = self.logits(x) 76 | return x 77 | 78 | 79 | def resnext101_32x4d(num_classes=1000, pretrained='imagenet'): 80 | model = ResNeXt101_32x4d(num_classes=num_classes) 81 | if pretrained is not None: 82 | settings = pretrained_settings['resnext101_32x4d'][pretrained] 83 | assert num_classes == settings['num_classes'], \ 84 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 85 | model.load_state_dict(model_zoo.load_url(settings['url'])) 86 | model.input_space = settings['input_space'] 87 | model.input_size = settings['input_size'] 88 | model.input_range = settings['input_range'] 89 | model.mean = settings['mean'] 90 | model.std = settings['std'] 91 | return model 92 | 93 | def resnext101_64x4d(num_classes=1000, pretrained='imagenet'): 94 | model = ResNeXt101_64x4d(num_classes=num_classes) 95 | if pretrained is not None: 96 | settings = pretrained_settings['resnext101_64x4d'][pretrained] 97 | assert num_classes == settings['num_classes'], \ 98 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 99 | model.load_state_dict(model_zoo.load_url(settings['url'])) 100 | model.input_space = settings['input_space'] 101 | model.input_size = settings['input_size'] 102 | model.input_range = settings['input_range'] 103 | model.mean = settings['mean'] 104 | model.std = settings['std'] 105 | return model 106 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/vggm.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import torch 3 | import torch.nn as nn 4 | from torch.autograd import Variable 5 | #from torch.legacy import nn as nnl 6 | import torch.utils.model_zoo as model_zoo 7 | 8 | __all__ = ['vggm'] 9 | 10 | pretrained_settings = { 11 | 'vggm': { 12 | 'imagenet': { 13 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/vggm-786f2434.pth', 14 | 'input_space': 'BGR', 15 | 'input_size': [3, 221, 221], 16 | 'input_range': [0, 255], 17 | 'mean': [123.68, 116.779, 103.939], 18 | 'std': [1, 1, 1], 19 | 'num_classes': 1000 20 | } 21 | } 22 | } 23 | 24 | class SpatialCrossMapLRN(nn.Module): 25 | def __init__(self, local_size=1, alpha=1.0, beta=0.75, k=1, ACROSS_CHANNELS=True): 26 | super(SpatialCrossMapLRN, self).__init__() 27 | self.ACROSS_CHANNELS = ACROSS_CHANNELS 28 | if ACROSS_CHANNELS: 29 | self.average=nn.AvgPool3d(kernel_size=(local_size, 1, 1), 30 | stride=1, 31 | padding=(int((local_size-1.0)/2), 0, 0)) 32 | else: 33 | self.average=nn.AvgPool2d(kernel_size=local_size, 34 | stride=1, 35 | padding=int((local_size-1.0)/2)) 36 | self.alpha = alpha 37 | self.beta = beta 38 | self.k = k 39 | 40 | def forward(self, x): 41 | if self.ACROSS_CHANNELS: 42 | div = x.pow(2).unsqueeze(1) 43 | div = self.average(div).squeeze(1) 44 | div = div.mul(self.alpha).add(self.k).pow(self.beta) 45 | else: 46 | div = x.pow(2) 47 | div = self.average(div) 48 | div = div.mul(self.alpha).add(self.k).pow(self.beta) 49 | x = x.div(div) 50 | return x 51 | 52 | class LambdaBase(nn.Sequential): 53 | def __init__(self, fn, *args): 54 | super(LambdaBase, self).__init__(*args) 55 | self.lambda_func = fn 56 | 57 | def forward_prepare(self, input): 58 | output = [] 59 | for module in self._modules.values(): 60 | output.append(module(input)) 61 | return output if output else input 62 | 63 | class Lambda(LambdaBase): 64 | def forward(self, input): 65 | return self.lambda_func(self.forward_prepare(input)) 66 | 67 | class VGGM(nn.Module): 68 | 69 | def __init__(self, num_classes=1000): 70 | super(VGGM, self).__init__() 71 | self.num_classes = num_classes 72 | self.features = nn.Sequential( 73 | nn.Conv2d(3,96,(7, 7),(2, 2)), 74 | nn.ReLU(), 75 | SpatialCrossMapLRN(5, 0.0005, 0.75, 2), 76 | nn.MaxPool2d((3, 3),(2, 2),(0, 0),ceil_mode=True), 77 | nn.Conv2d(96,256,(5, 5),(2, 2),(1, 1)), 78 | nn.ReLU(), 79 | SpatialCrossMapLRN(5, 0.0005, 0.75, 2), 80 | nn.MaxPool2d((3, 3),(2, 2),(0, 0),ceil_mode=True), 81 | nn.Conv2d(256,512,(3, 3),(1, 1),(1, 1)), 82 | nn.ReLU(), 83 | nn.Conv2d(512,512,(3, 3),(1, 1),(1, 1)), 84 | nn.ReLU(), 85 | nn.Conv2d(512,512,(3, 3),(1, 1),(1, 1)), 86 | nn.ReLU(), 87 | nn.MaxPool2d((3, 3),(2, 2),(0, 0),ceil_mode=True) 88 | ) 89 | self.classif = nn.Sequential( 90 | nn.Linear(18432,4096), 91 | nn.ReLU(), 92 | nn.Dropout(0.5), 93 | nn.Linear(4096,4096), 94 | nn.ReLU(), 95 | nn.Dropout(0.5), 96 | nn.Linear(4096,num_classes) 97 | ) 98 | 99 | def forward(self, x): 100 | x = self.features(x) 101 | x = x.view(x.size(0), -1) 102 | x = self.classif(x) 103 | return x 104 | 105 | def vggm(num_classes=1000, pretrained='imagenet'): 106 | if pretrained: 107 | settings = pretrained_settings['vggm'][pretrained] 108 | assert num_classes == settings['num_classes'], \ 109 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 110 | 111 | model = VGGM(num_classes=1000) 112 | model.load_state_dict(model_zoo.load_url(settings['url'])) 113 | 114 | model.input_space = settings['input_space'] 115 | model.input_size = settings['input_size'] 116 | model.input_range = settings['input_range'] 117 | model.mean = settings['mean'] 118 | model.std = settings['std'] 119 | else: 120 | model = VGGM(num_classes=num_classes) 121 | return model -------------------------------------------------------------------------------- /phase2/networks/preact_resnet.py: -------------------------------------------------------------------------------- 1 | '''Pre-activation ResNet in PyTorch. 2 | 3 | Reference: 4 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 5 | Identity Mappings in Deep Residual Networks. arXiv:1603.05027 6 | ''' 7 | import torch 8 | import torch.nn as nn 9 | import torch.nn.functional as F 10 | 11 | 12 | class PreActBlock(nn.Module): 13 | '''Pre-activation version of the BasicBlock.''' 14 | expansion = 1 15 | 16 | def __init__(self, in_planes, planes, stride=1): 17 | super(PreActBlock, self).__init__() 18 | self.bn1 = nn.BatchNorm2d(in_planes) 19 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 20 | self.bn2 = nn.BatchNorm2d(planes) 21 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 22 | 23 | if stride != 1 or in_planes != self.expansion*planes: 24 | self.shortcut = nn.Sequential( 25 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False) 26 | ) 27 | 28 | def forward(self, x): 29 | out = F.relu(self.bn1(x)) 30 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 31 | out = self.conv1(out) 32 | out = self.conv2(F.relu(self.bn2(out))) 33 | out += shortcut 34 | return out 35 | 36 | 37 | class PreActBottleneck(nn.Module): 38 | '''Pre-activation version of the original Bottleneck module.''' 39 | expansion = 4 40 | 41 | def __init__(self, in_planes, planes, stride=1): 42 | super(PreActBottleneck, self).__init__() 43 | self.bn1 = nn.BatchNorm2d(in_planes) 44 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 45 | self.bn2 = nn.BatchNorm2d(planes) 46 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 47 | self.bn3 = nn.BatchNorm2d(planes) 48 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 49 | 50 | if stride != 1 or in_planes != self.expansion*planes: 51 | self.shortcut = nn.Sequential( 52 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False) 53 | ) 54 | 55 | def forward(self, x): 56 | out = F.relu(self.bn1(x)) 57 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 58 | out = self.conv1(out) 59 | out = self.conv2(F.relu(self.bn2(out))) 60 | out = self.conv3(F.relu(self.bn3(out))) 61 | out += shortcut 62 | return out 63 | 64 | 65 | class PreActResNet(nn.Module): 66 | def __init__(self, block, num_blocks, num_classes=10): 67 | super(PreActResNet, self).__init__() 68 | self.in_planes = 64 69 | 70 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 71 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 72 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 73 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 74 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 75 | self.linear = nn.Linear(512*block.expansion, num_classes) 76 | 77 | def _make_layer(self, block, planes, num_blocks, stride): 78 | strides = [stride] + [1]*(num_blocks-1) 79 | layers = [] 80 | for stride in strides: 81 | layers.append(block(self.in_planes, planes, stride)) 82 | self.in_planes = planes * block.expansion 83 | return nn.Sequential(*layers) 84 | 85 | def forward(self, x): 86 | out = self.conv1(x) 87 | out = self.layer1(out) 88 | out = self.layer2(out) 89 | out = self.layer3(out) 90 | out = self.layer4(out) 91 | out = F.avg_pool2d(out, 4) 92 | out = out.view(out.size(0), -1) 93 | out = self.linear(out) 94 | return out 95 | 96 | 97 | def PreActResNet18(num_classes): 98 | return PreActResNet(PreActBlock, [2,2,2,2],num_classes=num_classes) 99 | 100 | def PreActResNet34(): 101 | return PreActResNet(PreActBlock, [3,4,6,3]) 102 | 103 | def PreActResNet50(): 104 | return PreActResNet(PreActBottleneck, [3,4,6,3]) 105 | 106 | def PreActResNet101(): 107 | return PreActResNet(PreActBottleneck, [3,4,23,3]) 108 | 109 | def PreActResNet152(): 110 | return PreActResNet(PreActBottleneck, [3,8,36,3]) 111 | 112 | ''' 113 | def test(): 114 | net = PreActResNet18() 115 | y = net((torch.randn(1,3,32,32))) 116 | print(y.size()) 117 | ''' 118 | # test() 119 | -------------------------------------------------------------------------------- /models/resnet.py: -------------------------------------------------------------------------------- 1 | '''ResNet in PyTorch. 2 | 3 | For Pre-activation ResNet, see 'preact_resnet.py'. 4 | 5 | Reference: 6 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 7 | Deep Residual Learning for Image Recognition. arXiv:1512.03385 8 | ''' 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | 14 | class BasicBlock(nn.Module): 15 | expansion = 1 16 | 17 | def __init__(self, in_planes, planes, stride=1): 18 | super(BasicBlock, self).__init__() 19 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 20 | self.bn1 = nn.BatchNorm2d(planes) 21 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 22 | self.bn2 = nn.BatchNorm2d(planes) 23 | 24 | self.shortcut = nn.Sequential() 25 | if stride != 1 or in_planes != self.expansion*planes: 26 | self.shortcut = nn.Sequential( 27 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 28 | nn.BatchNorm2d(self.expansion*planes) 29 | ) 30 | 31 | def forward(self, x): 32 | out = F.relu(self.bn1(self.conv1(x))) 33 | out = self.bn2(self.conv2(out)) 34 | out += self.shortcut(x) 35 | out = F.relu(out) 36 | return out 37 | 38 | 39 | class Bottleneck(nn.Module): 40 | expansion = 4 41 | 42 | def __init__(self, in_planes, planes, stride=1): 43 | super(Bottleneck, self).__init__() 44 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 45 | self.bn1 = nn.BatchNorm2d(planes) 46 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 47 | self.bn2 = nn.BatchNorm2d(planes) 48 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 49 | self.bn3 = nn.BatchNorm2d(self.expansion*planes) 50 | 51 | self.shortcut = nn.Sequential() 52 | if stride != 1 or in_planes != self.expansion*planes: 53 | self.shortcut = nn.Sequential( 54 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 55 | nn.BatchNorm2d(self.expansion*planes) 56 | ) 57 | 58 | def forward(self, x): 59 | out = F.relu(self.bn1(self.conv1(x))) 60 | out = F.relu(self.bn2(self.conv2(out))) 61 | out = self.bn3(self.conv3(out)) 62 | out += self.shortcut(x) 63 | out = F.relu(out) 64 | return out 65 | 66 | 67 | class ResNet(nn.Module): 68 | def __init__(self, block, num_blocks, num_classes=10): 69 | super(ResNet, self).__init__() 70 | self.in_planes = 64 71 | 72 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 73 | self.bn1 = nn.BatchNorm2d(64) 74 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 75 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 76 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 77 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 78 | self.linear = nn.Linear(512*block.expansion, num_classes) 79 | 80 | def _make_layer(self, block, planes, num_blocks, stride): 81 | strides = [stride] + [1]*(num_blocks-1) 82 | layers = [] 83 | for stride in strides: 84 | layers.append(block(self.in_planes, planes, stride)) 85 | self.in_planes = planes * block.expansion 86 | return nn.Sequential(*layers) 87 | 88 | def forward(self, x): 89 | out = F.relu(self.bn1(self.conv1(x))) 90 | out = self.layer1(out) 91 | out = self.layer2(out) 92 | out = self.layer3(out) 93 | out = self.layer4(out) 94 | out = F.avg_pool2d(out, 4) 95 | out = out.view(out.size(0), -1) 96 | out = self.linear(out) 97 | return out 98 | 99 | 100 | def ResNet18(num_classes): 101 | return ResNet(BasicBlock, [2,2,2,2],num_classes=num_classes) 102 | 103 | def ResNet34(num_classes): 104 | return ResNet(BasicBlock, [3,4,6,3],num_classes=num_classes) 105 | 106 | def ResNet50(num_classes): 107 | return ResNet(Bottleneck, [3,4,6,3],num_classes=num_classes) 108 | 109 | def ResNet101(num_classes): 110 | return ResNet(Bottleneck, [3,4,23,3],num_classes=num_classes) 111 | 112 | def ResNet152(num_classes): 113 | return ResNet(Bottleneck, [3,8,36,3],num_classes=num_classes) 114 | 115 | 116 | def test(): 117 | net = ResNet18() 118 | y = net(torch.randn(1,3,32,32)) 119 | print(y.size()) 120 | 121 | # test() 122 | -------------------------------------------------------------------------------- /phase2/networks/resnet.py: -------------------------------------------------------------------------------- 1 | '''ResNet in PyTorch. 2 | 3 | For Pre-activation ResNet, see 'preact_resnet.py'. 4 | 5 | Reference: 6 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 7 | Deep Residual Learning for Image Recognition. arXiv:1512.03385 8 | ''' 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | 14 | class BasicBlock(nn.Module): 15 | expansion = 1 16 | 17 | def __init__(self, in_planes, planes, stride=1): 18 | super(BasicBlock, self).__init__() 19 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 20 | self.bn1 = nn.BatchNorm2d(planes) 21 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 22 | self.bn2 = nn.BatchNorm2d(planes) 23 | 24 | self.shortcut = nn.Sequential() 25 | if stride != 1 or in_planes != self.expansion*planes: 26 | self.shortcut = nn.Sequential( 27 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 28 | nn.BatchNorm2d(self.expansion*planes) 29 | ) 30 | 31 | def forward(self, x): 32 | out = F.relu(self.bn1(self.conv1(x))) 33 | out = self.bn2(self.conv2(out)) 34 | out += self.shortcut(x) 35 | out = F.relu(out) 36 | return out 37 | 38 | 39 | class Bottleneck(nn.Module): 40 | expansion = 4 41 | 42 | def __init__(self, in_planes, planes, stride=1): 43 | super(Bottleneck, self).__init__() 44 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 45 | self.bn1 = nn.BatchNorm2d(planes) 46 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 47 | self.bn2 = nn.BatchNorm2d(planes) 48 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 49 | self.bn3 = nn.BatchNorm2d(self.expansion*planes) 50 | 51 | self.shortcut = nn.Sequential() 52 | if stride != 1 or in_planes != self.expansion*planes: 53 | self.shortcut = nn.Sequential( 54 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 55 | nn.BatchNorm2d(self.expansion*planes) 56 | ) 57 | 58 | def forward(self, x): 59 | out = F.relu(self.bn1(self.conv1(x))) 60 | out = F.relu(self.bn2(self.conv2(out))) 61 | out = self.bn3(self.conv3(out)) 62 | out += self.shortcut(x) 63 | out = F.relu(out) 64 | return out 65 | 66 | 67 | class ResNet(nn.Module): 68 | def __init__(self, block, num_blocks, num_classes=10): 69 | super(ResNet, self).__init__() 70 | self.in_planes = 64 71 | 72 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 73 | self.bn1 = nn.BatchNorm2d(64) 74 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 75 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 76 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 77 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 78 | self.linear = nn.Linear(512*block.expansion, num_classes) 79 | 80 | def _make_layer(self, block, planes, num_blocks, stride): 81 | strides = [stride] + [1]*(num_blocks-1) 82 | layers = [] 83 | for stride in strides: 84 | layers.append(block(self.in_planes, planes, stride)) 85 | self.in_planes = planes * block.expansion 86 | return nn.Sequential(*layers) 87 | 88 | def forward(self, x): 89 | out = F.relu(self.bn1(self.conv1(x))) 90 | out = self.layer1(out) 91 | out = self.layer2(out) 92 | out = self.layer3(out) 93 | out = self.layer4(out) 94 | out = F.avg_pool2d(out, 4) 95 | out = out.view(out.size(0), -1) 96 | out = self.linear(out) 97 | return out 98 | 99 | 100 | def ResNet18(num_classes): 101 | return ResNet(BasicBlock, [2,2,2,2],num_classes=num_classes) 102 | 103 | def ResNet34(num_classes): 104 | return ResNet(BasicBlock, [3,4,6,3],num_classes=num_classes) 105 | 106 | def ResNet50(num_classes): 107 | return ResNet(Bottleneck, [3,4,6,3],num_classes=num_classes) 108 | 109 | def ResNet101(num_classes): 110 | return ResNet(Bottleneck, [3,4,23,3],num_classes=num_classes) 111 | 112 | def ResNet152(num_classes): 113 | return ResNet(Bottleneck, [3,8,36,3],num_classes=num_classes) 114 | 115 | 116 | def test(): 117 | net = ResNet18() 118 | y = net(torch.randn(1,3,32,32)) 119 | print(y.size()) 120 | 121 | # test() 122 | -------------------------------------------------------------------------------- /phase2/augmentations.py: -------------------------------------------------------------------------------- 1 | # code in this file is adpated from rpmcruz/autoaugment 2 | # https://github.com/rpmcruz/autoaugment/blob/master/transformations.py 3 | import random 4 | 5 | import PIL, PIL.ImageOps, PIL.ImageEnhance, PIL.ImageDraw 6 | import numpy as np 7 | 8 | random_mirror = True 9 | 10 | 11 | def ShearX(img, v): # [-0.3, 0.3] 12 | assert -0.3 <= v <= 0.3 13 | if random_mirror and random.random() > 0.5: 14 | v = -v 15 | return img.transform(img.size, PIL.Image.AFFINE, (1, v, 0, 0, 1, 0)) 16 | 17 | 18 | def ShearY(img, v): # [-0.3, 0.3] 19 | assert -0.3 <= v <= 0.3 20 | if random_mirror and random.random() > 0.5: 21 | v = -v 22 | return img.transform(img.size, PIL.Image.AFFINE, (1, 0, 0, v, 1, 0)) 23 | 24 | 25 | def TranslateX(img, v): # [-150, 150] => percentage: [-0.45, 0.45] 26 | assert -0.45 <= v <= 0.45 27 | if random_mirror and random.random() > 0.5: 28 | v = -v 29 | v = v * img.size[0] 30 | return img.transform(img.size, PIL.Image.AFFINE, (1, 0, v, 0, 1, 0)) 31 | 32 | 33 | def TranslateY(img, v): # [-150, 150] => percentage: [-0.45, 0.45] 34 | assert -0.45 <= v <= 0.45 35 | if random_mirror and random.random() > 0.5: 36 | v = -v 37 | v = v * img.size[1] 38 | return img.transform(img.size, PIL.Image.AFFINE, (1, 0, 0, 0, 1, v)) 39 | 40 | 41 | def TranslateXAbs(img, v): # [-150, 150] => percentage: [-0.45, 0.45] 42 | assert 0 <= v <= 10 43 | if random.random() > 0.5: 44 | v = -v 45 | return img.transform(img.size, PIL.Image.AFFINE, (1, 0, v, 0, 1, 0)) 46 | 47 | 48 | def TranslateYAbs(img, v): # [-150, 150] => percentage: [-0.45, 0.45] 49 | assert 0 <= v <= 10 50 | if random.random() > 0.5: 51 | v = -v 52 | return img.transform(img.size, PIL.Image.AFFINE, (1, 0, 0, 0, 1, v)) 53 | 54 | 55 | def Rotate(img, v): # [-30, 30] 56 | assert -30 <= v <= 30 57 | if random_mirror and random.random() > 0.5: 58 | v = -v 59 | return img.rotate(v) 60 | 61 | 62 | def AutoContrast(img, _): 63 | return PIL.ImageOps.autocontrast(img) 64 | 65 | 66 | def Invert(img, _): 67 | return PIL.ImageOps.invert(img) 68 | 69 | 70 | def Equalize(img, _): 71 | return PIL.ImageOps.equalize(img) 72 | 73 | 74 | def Flip(img, _): # not from the paper 75 | return PIL.ImageOps.mirror(img) 76 | 77 | 78 | def Solarize(img, v): # [0, 256] 79 | assert 0 <= v <= 256 80 | return PIL.ImageOps.solarize(img, v) 81 | 82 | 83 | def Posterize(img, v): # [4, 8] 84 | assert 4 <= v <= 8 85 | v = int(v) 86 | return PIL.ImageOps.posterize(img, v) 87 | 88 | 89 | def Posterize2(img, v): # [0, 4] 90 | assert 0 <= v <= 4 91 | v = int(v) 92 | return PIL.ImageOps.posterize(img, v) 93 | 94 | 95 | def Contrast(img, v): # [0.1,1.9] 96 | assert 0.1 <= v <= 1.9 97 | return PIL.ImageEnhance.Contrast(img).enhance(v) 98 | 99 | 100 | def Color(img, v): # [0.1,1.9] 101 | assert 0.1 <= v <= 1.9 102 | return PIL.ImageEnhance.Color(img).enhance(v) 103 | 104 | 105 | def Brightness(img, v): # [0.1,1.9] 106 | assert 0.1 <= v <= 1.9 107 | return PIL.ImageEnhance.Brightness(img).enhance(v) 108 | 109 | 110 | def Sharpness(img, v): # [0.1,1.9] 111 | assert 0.1 <= v <= 1.9 112 | return PIL.ImageEnhance.Sharpness(img).enhance(v) 113 | 114 | 115 | def Cutout(img, v): # [0, 60] => percentage: [0, 0.2] 116 | assert 0.0 <= v <= 0.2 117 | if v <= 0.: 118 | return img 119 | 120 | v = v * img.size[0] 121 | 122 | return CutoutAbs(img, v) 123 | 124 | # x0 = np.random.uniform(w - v) 125 | # y0 = np.random.uniform(h - v) 126 | # xy = (x0, y0, x0 + v, y0 + v) 127 | # color = (127, 127, 127) 128 | # img = img.copy() 129 | # PIL.ImageDraw.Draw(img).rectangle(xy, color) 130 | # return img 131 | 132 | 133 | def CutoutAbs(img, v): # [0, 60] => percentage: [0, 0.2] 134 | # assert 0 <= v <= 20 135 | if v < 0: 136 | return img 137 | w, h = img.size 138 | x0 = np.random.uniform(w) 139 | y0 = np.random.uniform(h) 140 | 141 | x0 = int(max(0, x0 - v / 2.)) 142 | y0 = int(max(0, y0 - v / 2.)) 143 | x1 = min(w, x0 + v) 144 | y1 = min(h, y0 + v) 145 | 146 | xy = (x0, y0, x1, y1) 147 | color = (125, 123, 114) 148 | # color = (0, 0, 0) 149 | img = img.copy() 150 | PIL.ImageDraw.Draw(img).rectangle(xy, color) 151 | return img 152 | 153 | 154 | def SamplePairing(imgs): # [0, 0.4] 155 | def f(img1, v): 156 | i = np.random.choice(len(imgs)) 157 | img2 = PIL.Image.fromarray(imgs[i]) 158 | return PIL.Image.blend(img1, img2, v) 159 | 160 | return f 161 | 162 | 163 | def augment_list(for_autoaug=True): # 16 operations and their ranges 164 | l = [ 165 | (ShearX, -0.3, 0.3), # 0 166 | (ShearY, -0.3, 0.3), # 1 167 | (TranslateX, -0.45, 0.45), # 2 168 | (TranslateY, -0.45, 0.45), # 3 169 | (Rotate, -30, 30), # 4 170 | (AutoContrast, 0, 1), # 5 171 | (Invert, 0, 1), # 6 172 | (Equalize, 0, 1), # 7 173 | (Solarize, 0, 256), # 8 174 | (Posterize, 4, 8), # 9 175 | (Contrast, 0.1, 1.9), # 10 176 | (Color, 0.1, 1.9), # 11 177 | (Brightness, 0.1, 1.9), # 12 178 | (Sharpness, 0.1, 1.9), # 13 179 | (Cutout, 0, 0.2), # 14 180 | # (SamplePairing(imgs), 0, 0.4), # 15 181 | ] 182 | if for_autoaug: 183 | l += [ 184 | (CutoutAbs, 0, 20), # compatible with auto-augment 185 | (Posterize2, 0, 4), # 9 186 | (TranslateXAbs, 0, 10), # 9 187 | (TranslateYAbs, 0, 10), # 9 188 | ] 189 | return l 190 | 191 | 192 | augment_dict = {fn.__name__: (fn, v1, v2) for fn, v1, v2 in augment_list()} 193 | 194 | 195 | def get_augment(name): 196 | return augment_dict[name] 197 | 198 | 199 | def apply_augment(img, name, level): 200 | augment_fn, low, high = get_augment(name) 201 | return augment_fn(img.copy(), level * (high - low) + low) 202 | -------------------------------------------------------------------------------- /phase2/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | import copy 4 | import hashlib 5 | import errno 6 | import numpy as np 7 | from numpy.testing import assert_array_almost_equal 8 | 9 | 10 | def check_integrity(fpath, md5): 11 | if not os.path.isfile(fpath): 12 | return False 13 | md5o = hashlib.md5() 14 | with open(fpath, 'rb') as f: 15 | # read in 1MB chunks 16 | for chunk in iter(lambda: f.read(1024 * 1024), b''): 17 | md5o.update(chunk) 18 | md5c = md5o.hexdigest() 19 | if md5c != md5: 20 | return False 21 | return True 22 | 23 | 24 | def download_url(url, root, filename, md5): 25 | from six.moves import urllib 26 | 27 | root = os.path.expanduser(root) 28 | fpath = os.path.join(root, filename) 29 | 30 | try: 31 | os.makedirs(root) 32 | except OSError as e: 33 | if e.errno == errno.EEXIST: 34 | pass 35 | else: 36 | raise 37 | 38 | # downloads file 39 | if os.path.isfile(fpath) and check_integrity(fpath, md5): 40 | print('Using downloaded and verified file: ' + fpath) 41 | else: 42 | try: 43 | print('Downloading ' + url + ' to ' + fpath) 44 | urllib.request.urlretrieve(url, fpath) 45 | except: 46 | if url[:5] == 'https': 47 | url = url.replace('https:', 'http:') 48 | print('Failed download. Trying https -> http instead.' 49 | ' Downloading ' + url + ' to ' + fpath) 50 | urllib.request.urlretrieve(url, fpath) 51 | 52 | 53 | def list_dir(root, prefix=False): 54 | """List all directories at a given root 55 | 56 | Args: 57 | root (str): Path to directory whose folders need to be listed 58 | prefix (bool, optional): If true, prepends the path to each result, otherwise 59 | only returns the name of the directories found 60 | """ 61 | root = os.path.expanduser(root) 62 | directories = list( 63 | filter( 64 | lambda p: os.path.isdir(os.path.join(root, p)), 65 | os.listdir(root) 66 | ) 67 | ) 68 | 69 | if prefix is True: 70 | directories = [os.path.join(root, d) for d in directories] 71 | 72 | return directories 73 | 74 | 75 | def list_files(root, suffix, prefix=False): 76 | """List all files ending with a suffix at a given root 77 | 78 | Args: 79 | root (str): Path to directory whose folders need to be listed 80 | suffix (str or tuple): Suffix of the files to match, e.g. '.png' or ('.jpg', '.png'). 81 | It uses the Python "str.endswith" method and is passed directly 82 | prefix (bool, optional): If true, prepends the path to each result, otherwise 83 | only returns the name of the files found 84 | """ 85 | root = os.path.expanduser(root) 86 | files = list( 87 | filter( 88 | lambda p: os.path.isfile(os.path.join(root, p)) and p.endswith(suffix), 89 | os.listdir(root) 90 | ) 91 | ) 92 | 93 | if prefix is True: 94 | files = [os.path.join(root, d) for d in files] 95 | 96 | return files 97 | 98 | # basic function# 99 | def multiclass_noisify(y, P, random_state=0): 100 | """ Flip classes according to transition probability matrix T. 101 | It expects a number between 0 and the number of classes - 1. 102 | """ 103 | #print np.max(y), P.shape[0] 104 | assert P.shape[0] == P.shape[1] 105 | assert np.max(y) < P.shape[0] 106 | 107 | # row stochastic matrix 108 | assert_array_almost_equal(P.sum(axis=1), np.ones(P.shape[1])) 109 | assert (P >= 0.0).all() 110 | 111 | m = y.shape[0] 112 | #print m 113 | new_y = y.copy() 114 | flipper = np.random.RandomState(random_state) 115 | 116 | for idx in np.arange(m): 117 | i = y[idx] 118 | # draw a vector with only an 1 119 | flipped = flipper.multinomial(1, P[i, :][0], 1)[0] 120 | new_y[idx] = np.where(flipped == 1)[0] 121 | 122 | return new_y 123 | 124 | 125 | # noisify_pairflip call the function "multiclass_noisify" 126 | def noisify_pairflip(y_train, noise, random_state=None, nb_classes=10): 127 | """mistakes: 128 | flip in the pair 129 | """ 130 | P = np.eye(nb_classes) 131 | n = noise 132 | 133 | if n > 0.0: 134 | # 0 -> 1 135 | P[0, 0], P[0, 1] = 1. - n, n 136 | for i in range(1, nb_classes-1): 137 | P[i, i], P[i, i + 1] = 1. - n, n 138 | P[nb_classes-1, nb_classes-1], P[nb_classes-1, 0] = 1. - n, n 139 | 140 | y_train_noisy = multiclass_noisify(y_train, P=P, 141 | random_state=random_state) 142 | actual_noise = (y_train_noisy != y_train).mean() 143 | assert actual_noise > 0.0 144 | print('Actual noise %.2f' % actual_noise) 145 | y_train = y_train_noisy 146 | #print P 147 | 148 | return y_train, actual_noise 149 | 150 | def noisify_multiclass_symmetric(y_train, noise, random_state=None, nb_classes=10): 151 | """mistakes: 152 | flip in the symmetric way 153 | """ 154 | P = np.ones((nb_classes, nb_classes)) 155 | n = noise 156 | P = (n / (nb_classes - 1)) * P 157 | 158 | if n > 0.0: 159 | # 0 -> 1 160 | P[0, 0] = 1. - n 161 | for i in range(1, nb_classes-1): 162 | P[i, i] = 1. - n 163 | P[nb_classes-1, nb_classes-1] = 1. - n 164 | 165 | y_train_noisy = multiclass_noisify(y_train, P=P, 166 | random_state=random_state) 167 | actual_noise = (y_train_noisy != y_train).mean() 168 | assert actual_noise > 0.0 169 | print('Actual noise %.5f' % actual_noise) 170 | y_train = y_train_noisy 171 | #print P 172 | 173 | return y_train, actual_noise 174 | 175 | def noisify(nb_classes=10, train_labels=None, noise_type=None, noise_rate=0, random_state=0): 176 | if noise_type == 'pairflip': 177 | train_noisy_labels, actual_noise_rate = noisify_pairflip(train_labels, noise_rate, random_state=0, nb_classes=nb_classes) 178 | if noise_type == 'symmetric': 179 | train_noisy_labels, actual_noise_rate = noisify_multiclass_symmetric(train_labels, noise_rate, random_state=0, nb_classes=nb_classes) 180 | return train_noisy_labels, actual_noise_rate 181 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/cafferesnet.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import math 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | import torch.utils.model_zoo as model_zoo 7 | 8 | pretrained_settings = { 9 | 'cafferesnet101': { 10 | 'imagenet': { 11 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/cafferesnet101-9d633cc0.pth', 12 | 'input_space': 'BGR', 13 | 'input_size': [3, 224, 224], 14 | 'input_range': [0, 255], 15 | 'mean': [102.9801, 115.9465, 122.7717], 16 | 'std': [1, 1, 1], 17 | 'num_classes': 1000 18 | } 19 | } 20 | } 21 | 22 | 23 | def conv3x3(in_planes, out_planes, stride=1): 24 | "3x3 convolution with padding" 25 | return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, 26 | padding=1, bias=False) 27 | 28 | 29 | class BasicBlock(nn.Module): 30 | expansion = 1 31 | 32 | def __init__(self, inplanes, planes, stride=1, downsample=None): 33 | super(BasicBlock, self).__init__() 34 | self.conv1 = conv3x3(inplanes, planes, stride) 35 | self.bn1 = nn.BatchNorm2d(planes) 36 | self.relu = nn.ReLU(inplace=True) 37 | self.conv2 = conv3x3(planes, planes) 38 | self.bn2 = nn.BatchNorm2d(planes) 39 | self.downsample = downsample 40 | self.stride = stride 41 | 42 | def forward(self, x): 43 | residual = x 44 | 45 | out = self.conv1(x) 46 | out = self.bn1(out) 47 | out = self.relu(out) 48 | 49 | out = self.conv2(out) 50 | out = self.bn2(out) 51 | 52 | if self.downsample is not None: 53 | residual = self.downsample(x) 54 | 55 | out += residual 56 | out = self.relu(out) 57 | 58 | return out 59 | 60 | 61 | class Bottleneck(nn.Module): 62 | expansion = 4 63 | 64 | def __init__(self, inplanes, planes, stride=1, downsample=None): 65 | super(Bottleneck, self).__init__() 66 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False) # change 67 | self.bn1 = nn.BatchNorm2d(planes) 68 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, # change 69 | padding=1, bias=False) 70 | self.bn2 = nn.BatchNorm2d(planes) 71 | self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) 72 | self.bn3 = nn.BatchNorm2d(planes * 4) 73 | self.relu = nn.ReLU(inplace=True) 74 | self.downsample = downsample 75 | self.stride = stride 76 | 77 | def forward(self, x): 78 | residual = x 79 | 80 | out = self.conv1(x) 81 | out = self.bn1(out) 82 | out = self.relu(out) 83 | 84 | out = self.conv2(out) 85 | out = self.bn2(out) 86 | out = self.relu(out) 87 | 88 | out = self.conv3(out) 89 | out = self.bn3(out) 90 | 91 | if self.downsample is not None: 92 | residual = self.downsample(x) 93 | 94 | out += residual 95 | out = self.relu(out) 96 | 97 | return out 98 | 99 | 100 | class ResNet(nn.Module): 101 | 102 | def __init__(self, block, layers, num_classes=1000): 103 | self.inplanes = 64 104 | super(ResNet, self).__init__() 105 | self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, 106 | bias=False) 107 | self.bn1 = nn.BatchNorm2d(64) 108 | self.relu = nn.ReLU(inplace=True) 109 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=0, ceil_mode=True) # change 110 | self.layer1 = self._make_layer(block, 64, layers[0]) 111 | self.layer2 = self._make_layer(block, 128, layers[1], stride=2) 112 | self.layer3 = self._make_layer(block, 256, layers[2], stride=2) 113 | self.layer4 = self._make_layer(block, 512, layers[3], stride=2) 114 | # it is slightly better whereas slower to set stride = 1 115 | # self.layer4 = self._make_layer(block, 512, layers[3], stride=1) 116 | self.avgpool = nn.AvgPool2d(7) 117 | self.last_linear = nn.Linear(512 * block.expansion, num_classes) 118 | 119 | for m in self.modules(): 120 | if isinstance(m, nn.Conv2d): 121 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 122 | m.weight.data.normal_(0, math.sqrt(2. / n)) 123 | elif isinstance(m, nn.BatchNorm2d): 124 | m.weight.data.fill_(1) 125 | m.bias.data.zero_() 126 | 127 | def _make_layer(self, block, planes, blocks, stride=1): 128 | downsample = None 129 | if stride != 1 or self.inplanes != planes * block.expansion: 130 | downsample = nn.Sequential( 131 | nn.Conv2d(self.inplanes, planes * block.expansion, 132 | kernel_size=1, stride=stride, bias=False), 133 | nn.BatchNorm2d(planes * block.expansion), 134 | ) 135 | 136 | layers = [] 137 | layers.append(block(self.inplanes, planes, stride, downsample)) 138 | self.inplanes = planes * block.expansion 139 | for i in range(1, blocks): 140 | layers.append(block(self.inplanes, planes)) 141 | 142 | return nn.Sequential(*layers) 143 | 144 | def features(self, x): 145 | x = self.conv1(x) 146 | x = self.bn1(x) 147 | x = self.relu(x) 148 | x = self.maxpool(x) 149 | 150 | x = self.layer1(x) 151 | x = self.layer2(x) 152 | x = self.layer3(x) 153 | x = self.layer4(x) 154 | return x 155 | 156 | def logits(self, x): 157 | x = self.avgpool(x) 158 | x = x.view(x.size(0), -1) 159 | x = self.last_linear(x) 160 | return x 161 | 162 | def forward(self, x): 163 | x = self.features(x) 164 | x = self.logits(x) 165 | return x 166 | 167 | 168 | def cafferesnet101(num_classes=1000, pretrained='imagenet'): 169 | """Constructs a ResNet-101 model. 170 | Args: 171 | pretrained (bool): If True, returns a model pre-trained on ImageNet 172 | """ 173 | model = ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes) 174 | if pretrained is not None: 175 | settings = pretrained_settings['cafferesnet101'][pretrained] 176 | assert num_classes == settings['num_classes'], \ 177 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 178 | model.load_state_dict(model_zoo.load_url(settings['url'])) 179 | model.input_space = settings['input_space'] 180 | model.input_size = settings['input_size'] 181 | model.input_range = settings['input_range'] 182 | model.mean = settings['mean'] 183 | model.std = settings['std'] 184 | return model -------------------------------------------------------------------------------- /data/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | import copy 4 | import hashlib 5 | import errno 6 | import numpy as np 7 | from numpy.testing import assert_array_almost_equal 8 | import torch 9 | import torch.nn.functional as F 10 | 11 | def check_integrity(fpath, md5): 12 | if not os.path.isfile(fpath): 13 | return False 14 | md5o = hashlib.md5() 15 | with open(fpath, 'rb') as f: 16 | # read in 1MB chunks 17 | for chunk in iter(lambda: f.read(1024 * 1024), b''): 18 | md5o.update(chunk) 19 | md5c = md5o.hexdigest() 20 | if md5c != md5: 21 | return False 22 | return True 23 | 24 | 25 | def download_url(url, root, filename, md5): 26 | from six.moves import urllib 27 | 28 | root = os.path.expanduser(root) 29 | fpath = os.path.join(root, filename) 30 | 31 | try: 32 | os.makedirs(root) 33 | except OSError as e: 34 | if e.errno == errno.EEXIST: 35 | pass 36 | else: 37 | raise 38 | 39 | # downloads file 40 | if os.path.isfile(fpath) and check_integrity(fpath, md5): 41 | print('Using downloaded and verified file: ' + fpath) 42 | else: 43 | try: 44 | print('Downloading ' + url + ' to ' + fpath) 45 | urllib.request.urlretrieve(url, fpath) 46 | except: 47 | if url[:5] == 'https': 48 | url = url.replace('https:', 'http:') 49 | print('Failed download. Trying https -> http instead.' 50 | ' Downloading ' + url + ' to ' + fpath) 51 | urllib.request.urlretrieve(url, fpath) 52 | 53 | 54 | def list_dir(root, prefix=False): 55 | """List all directories at a given root 56 | 57 | Args: 58 | root (str): Path to directory whose folders need to be listed 59 | prefix (bool, optional): If true, prepends the path to each result, otherwise 60 | only returns the name of the directories found 61 | """ 62 | root = os.path.expanduser(root) 63 | directories = list( 64 | filter( 65 | lambda p: os.path.isdir(os.path.join(root, p)), 66 | os.listdir(root) 67 | ) 68 | ) 69 | 70 | if prefix is True: 71 | directories = [os.path.join(root, d) for d in directories] 72 | 73 | return directories 74 | 75 | 76 | def list_files(root, suffix, prefix=False): 77 | """List all files ending with a suffix at a given root 78 | 79 | Args: 80 | root (str): Path to directory whose folders need to be listed 81 | suffix (str or tuple): Suffix of the files to match, e.g. '.png' or ('.jpg', '.png'). 82 | It uses the Python "str.endswith" method and is passed directly 83 | prefix (bool, optional): If true, prepends the path to each result, otherwise 84 | only returns the name of the files found 85 | """ 86 | root = os.path.expanduser(root) 87 | files = list( 88 | filter( 89 | lambda p: os.path.isfile(os.path.join(root, p)) and p.endswith(suffix), 90 | os.listdir(root) 91 | ) 92 | ) 93 | 94 | if prefix is True: 95 | files = [os.path.join(root, d) for d in files] 96 | 97 | return files 98 | 99 | # basic function# 100 | def multiclass_noisify(y, P, random_state=0): 101 | """ Flip classes according to transition probability matrix T. 102 | It expects a number between 0 and the number of classes - 1. 103 | """ 104 | #print np.max(y), P.shape[0] 105 | assert P.shape[0] == P.shape[1] 106 | assert np.max(y) < P.shape[0] 107 | 108 | # row stochastic matrix 109 | assert_array_almost_equal(P.sum(axis=1), np.ones(P.shape[1])) 110 | assert (P >= 0.0).all() 111 | 112 | m = y.shape[0] 113 | #print m 114 | new_y = y.copy() 115 | flipper = np.random.RandomState(random_state) 116 | 117 | for idx in np.arange(m): 118 | i = y[idx] 119 | # draw a vector with only an 1 120 | flipped = flipper.multinomial(1, P[i, :][0], 1)[0] 121 | new_y[idx] = np.where(flipped == 1)[0] 122 | 123 | return new_y 124 | 125 | 126 | # noisify_pairflip call the function "multiclass_noisify" 127 | def noisify_pairflip(y_train, noise, random_state=None, nb_classes=10): 128 | """mistakes: 129 | flip in the pair 130 | """ 131 | P = np.eye(nb_classes) 132 | n = noise 133 | 134 | if n > 0.0: 135 | # 0 -> 1 136 | P[0, 0], P[0, 1] = 1. - n, n 137 | for i in range(1, nb_classes-1): 138 | P[i, i], P[i, i + 1] = 1. - n, n 139 | P[nb_classes-1, nb_classes-1], P[nb_classes-1, 0] = 1. - n, n 140 | 141 | y_train_noisy = multiclass_noisify(y_train, P=P, 142 | random_state=random_state) 143 | actual_noise = (y_train_noisy != y_train).mean() 144 | assert actual_noise > 0.0 145 | print('Actual noise %.2f' % actual_noise) 146 | y_train = y_train_noisy 147 | #print P 148 | 149 | return y_train, actual_noise 150 | 151 | def noisify_multiclass_symmetric(y_train, noise, random_state=None, nb_classes=10): 152 | """mistakes: 153 | flip in the symmetric way 154 | """ 155 | P = np.ones((nb_classes, nb_classes)) 156 | n = noise 157 | P = (n / (nb_classes - 1)) * P 158 | 159 | if n > 0.0: 160 | # 0 -> 1 161 | P[0, 0] = 1. - n 162 | for i in range(1, nb_classes-1): 163 | P[i, i] = 1. - n 164 | P[nb_classes-1, nb_classes-1] = 1. - n 165 | 166 | y_train_noisy = multiclass_noisify(y_train, P=P, 167 | random_state=random_state) 168 | actual_noise = (y_train_noisy != y_train).mean() 169 | assert actual_noise > 0.0 170 | print('Actual noise %.2f' % actual_noise) 171 | y_train = y_train_noisy 172 | #print P 173 | 174 | return y_train, actual_noise 175 | 176 | def noisify(dataset='mnist', nb_classes=10, train_labels=None, noise_type=None, noise_rate=0, random_state=0): 177 | if noise_type == 'pairflip': 178 | train_noisy_labels, actual_noise_rate = noisify_pairflip(train_labels, noise_rate, random_state=0, nb_classes=nb_classes) 179 | if noise_type == 'symmetric': 180 | train_noisy_labels, actual_noise_rate = noisify_multiclass_symmetric(train_labels, noise_rate, random_state=0, nb_classes=nb_classes) 181 | return train_noisy_labels, actual_noise_rate 182 | 183 | 184 | 185 | def noisify_instance(train_data,train_labels,noise_rate): 186 | if max(train_labels)>10: 187 | num_class = 100 188 | else: 189 | num_class = 10 190 | np.random.seed(0) 191 | 192 | q_ = np.random.normal(loc=noise_rate,scale=0.1,size=1000000) 193 | q = [] 194 | for pro in q_: 195 | if 0 < pro < 1: 196 | q.append(pro) 197 | if len(q)==50000: 198 | break 199 | 200 | w = np.random.normal(loc=0,scale=1,size=(32*32*3,num_class)) 201 | 202 | noisy_labels = [] 203 | for i, sample in enumerate(train_data): 204 | sample = sample.flatten() 205 | p_all = np.matmul(sample,w) 206 | p_all[train_labels[i]] = -1000000 207 | p_all = q[i]* F.softmax(torch.tensor(p_all),dim=0).numpy() 208 | p_all[train_labels[i]] = 1 - q[i] 209 | noisy_labels.append(np.random.choice(np.arange(num_class),p=p_all/sum(p_all))) 210 | over_all_noise_rate = 1 - float(torch.tensor(train_labels).eq(torch.tensor(noisy_labels)).sum())/50000 211 | return noisy_labels, over_all_noise_rate -------------------------------------------------------------------------------- /phase2/pretrainedmodels/datasets/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import math 3 | from six.moves.urllib.request import urlretrieve 4 | 5 | import torch 6 | from PIL import Image 7 | from tqdm import tqdm 8 | 9 | def load_imagenet_classes(path_synsets='data/imagenet_synsets.txt', 10 | path_classes='data/imagenet_classes.txt'): 11 | with open(path_synsets, 'r') as f: 12 | synsets = f.readlines() 13 | 14 | synsets = [x.strip() for x in synsets] 15 | splits = [line.split(' ') for line in synsets] 16 | key_to_classname = {spl[0]:' '.join(spl[1:]) for spl in splits} 17 | 18 | with open(path_classes, 'r') as f: 19 | class_id_to_key = f.readlines() 20 | 21 | class_id_to_key = [x.strip() for x in class_id_to_key] 22 | 23 | cid_to_cname = [] 24 | for i in range(len(class_id_to_key)): 25 | key = class_id_to_key[i] 26 | cname = key_to_classname[key] 27 | cid_to_cname.append(cname) 28 | 29 | return cid_to_cname 30 | 31 | 32 | class Warp(object): 33 | def __init__(self, size, interpolation=Image.BILINEAR): 34 | self.size = int(size) 35 | self.interpolation = interpolation 36 | 37 | def __call__(self, img): 38 | return img.resize((self.size, self.size), self.interpolation) 39 | 40 | def __str__(self): 41 | return self.__class__.__name__ + ' (size={size}, interpolation={interpolation})'.format(size=self.size, 42 | interpolation=self.interpolation) 43 | 44 | 45 | def download_url(url, destination=None, progress_bar=True): 46 | """Download a URL to a local file. 47 | 48 | Parameters 49 | ---------- 50 | url : str 51 | The URL to download. 52 | destination : str, None 53 | The destination of the file. If None is given the file is saved to a temporary directory. 54 | progress_bar : bool 55 | Whether to show a command-line progress bar while downloading. 56 | 57 | Returns 58 | ------- 59 | filename : str 60 | The location of the downloaded file. 61 | 62 | Notes 63 | ----- 64 | Progress bar use/example adapted from tqdm documentation: https://github.com/tqdm/tqdm 65 | """ 66 | 67 | def my_hook(t): 68 | last_b = [0] 69 | 70 | def inner(b=1, bsize=1, tsize=None): 71 | if tsize is not None: 72 | t.total = tsize 73 | if b > 0: 74 | t.update((b - last_b[0]) * bsize) 75 | last_b[0] = b 76 | 77 | return inner 78 | 79 | if progress_bar: 80 | with tqdm(unit='B', unit_scale=True, miniters=1, desc=url.split('/')[-1]) as t: 81 | filename, _ = urlretrieve(url, filename=destination, reporthook=my_hook(t)) 82 | else: 83 | filename, _ = urlretrieve(url, filename=destination) 84 | 85 | 86 | class AveragePrecisionMeter(object): 87 | """ 88 | The APMeter measures the average precision per class. 89 | The APMeter is designed to operate on `NxK` Tensors `output` and 90 | `target`, and optionally a `Nx1` Tensor weight where (1) the `output` 91 | contains model output scores for `N` examples and `K` classes that ought to 92 | be higher when the model is more convinced that the example should be 93 | positively labeled, and smaller when the model believes the example should 94 | be negatively labeled (for instance, the output of a sigmoid function); (2) 95 | the `target` contains only values 0 (for negative examples) and 1 96 | (for positive examples); and (3) the `weight` ( > 0) represents weight for 97 | each sample. 98 | """ 99 | 100 | def __init__(self, difficult_examples=False): 101 | super(AveragePrecisionMeter, self).__init__() 102 | self.reset() 103 | self.difficult_examples = difficult_examples 104 | 105 | def reset(self): 106 | """Resets the meter with empty member variables""" 107 | self.scores = torch.FloatTensor(torch.FloatStorage()) 108 | self.targets = torch.LongTensor(torch.LongStorage()) 109 | 110 | def add(self, output, target): 111 | """ 112 | Args: 113 | output (Tensor): NxK tensor that for each of the N examples 114 | indicates the probability of the example belonging to each of 115 | the K classes, according to the model. The probabilities should 116 | sum to one over all classes 117 | target (Tensor): binary NxK tensort that encodes which of the K 118 | classes are associated with the N-th input 119 | (eg: a row [0, 1, 0, 1] indicates that the example is 120 | associated with classes 2 and 4) 121 | weight (optional, Tensor): Nx1 tensor representing the weight for 122 | each example (each weight > 0) 123 | """ 124 | if not torch.is_tensor(output): 125 | output = torch.from_numpy(output) 126 | if not torch.is_tensor(target): 127 | target = torch.from_numpy(target) 128 | 129 | if output.dim() == 1: 130 | output = output.view(-1, 1) 131 | else: 132 | assert output.dim() == 2, \ 133 | 'wrong output size (should be 1D or 2D with one column \ 134 | per class)' 135 | if target.dim() == 1: 136 | target = target.view(-1, 1) 137 | else: 138 | assert target.dim() == 2, \ 139 | 'wrong target size (should be 1D or 2D with one column \ 140 | per class)' 141 | if self.scores.numel() > 0: 142 | assert target.size(1) == self.targets.size(1), \ 143 | 'dimensions for output should match previously added examples.' 144 | 145 | # make sure storage is of sufficient size 146 | if self.scores.storage().size() < self.scores.numel() + output.numel(): 147 | new_size = math.ceil(self.scores.storage().size() * 1.5) 148 | self.scores.storage().resize_(int(new_size + output.numel())) 149 | self.targets.storage().resize_(int(new_size + output.numel())) 150 | 151 | # store scores and targets 152 | offset = self.scores.size(0) if self.scores.dim() > 0 else 0 153 | self.scores.resize_(offset + output.size(0), output.size(1)) 154 | self.targets.resize_(offset + target.size(0), target.size(1)) 155 | self.scores.narrow(0, offset, output.size(0)).copy_(output) 156 | self.targets.narrow(0, offset, target.size(0)).copy_(target) 157 | 158 | def value(self): 159 | """Returns the model's average precision for each class 160 | Return: 161 | ap (FloatTensor): 1xK tensor, with avg precision for each class k 162 | """ 163 | 164 | if self.scores.numel() == 0: 165 | return 0 166 | ap = torch.zeros(self.scores.size(1)) 167 | rg = torch.arange(1, self.scores.size(0)).float() 168 | 169 | # compute average precision for each class 170 | for k in range(self.scores.size(1)): 171 | # sort scores 172 | scores = self.scores[:, k] 173 | targets = self.targets[:, k] 174 | 175 | # compute average precision 176 | ap[k] = AveragePrecisionMeter.average_precision(scores, targets, self.difficult_examples) 177 | return ap 178 | 179 | @staticmethod 180 | def average_precision(output, target, difficult_examples=True): 181 | 182 | # sort examples 183 | sorted, indices = torch.sort(output, dim=0, descending=True) 184 | 185 | # Computes prec@i 186 | pos_count = 0. 187 | total_count = 0. 188 | precision_at_i = 0. 189 | for i in indices: 190 | label = target[i] 191 | if difficult_examples and label == 0: 192 | continue 193 | if label == 1: 194 | pos_count += 1 195 | total_count += 1 196 | if label == 1: 197 | precision_at_i += pos_count / total_count 198 | precision_at_i /= pos_count 199 | return precision_at_i -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/fbresnet.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import torch.nn as nn 3 | import math 4 | import torch.utils.model_zoo as model_zoo 5 | 6 | 7 | __all__ = ['FBResNet', 8 | #'fbresnet18', 'fbresnet34', 'fbresnet50', 'fbresnet101', 9 | 'fbresnet152'] 10 | 11 | pretrained_settings = { 12 | 'fbresnet152': { 13 | 'imagenet': { 14 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/fbresnet152-2e20f6b4.pth', 15 | 'input_space': 'RGB', 16 | 'input_size': [3, 224, 224], 17 | 'input_range': [0, 1], 18 | 'mean': [0.485, 0.456, 0.406], 19 | 'std': [0.229, 0.224, 0.225], 20 | 'num_classes': 1000 21 | } 22 | } 23 | } 24 | 25 | 26 | def conv3x3(in_planes, out_planes, stride=1): 27 | "3x3 convolution with padding" 28 | return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, 29 | padding=1, bias=True) 30 | 31 | 32 | class BasicBlock(nn.Module): 33 | expansion = 1 34 | 35 | def __init__(self, inplanes, planes, stride=1, downsample=None): 36 | super(BasicBlock, self).__init__() 37 | self.conv1 = conv3x3(inplanes, planes, stride) 38 | self.bn1 = nn.BatchNorm2d(planes) 39 | self.relu = nn.ReLU(inplace=True) 40 | self.conv2 = conv3x3(planes, planes) 41 | self.bn2 = nn.BatchNorm2d(planes) 42 | self.downsample = downsample 43 | self.stride = stride 44 | 45 | def forward(self, x): 46 | residual = x 47 | 48 | out = self.conv1(x) 49 | out = self.bn1(out) 50 | out = self.relu(out) 51 | 52 | out = self.conv2(out) 53 | out = self.bn2(out) 54 | 55 | if self.downsample is not None: 56 | residual = self.downsample(x) 57 | 58 | out += residual 59 | out = self.relu(out) 60 | 61 | return out 62 | 63 | 64 | class Bottleneck(nn.Module): 65 | expansion = 4 66 | 67 | def __init__(self, inplanes, planes, stride=1, downsample=None): 68 | super(Bottleneck, self).__init__() 69 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=True) 70 | self.bn1 = nn.BatchNorm2d(planes) 71 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, 72 | padding=1, bias=True) 73 | self.bn2 = nn.BatchNorm2d(planes) 74 | self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=True) 75 | self.bn3 = nn.BatchNorm2d(planes * 4) 76 | self.relu = nn.ReLU(inplace=True) 77 | self.downsample = downsample 78 | self.stride = stride 79 | 80 | def forward(self, x): 81 | residual = x 82 | 83 | out = self.conv1(x) 84 | out = self.bn1(out) 85 | out = self.relu(out) 86 | 87 | out = self.conv2(out) 88 | out = self.bn2(out) 89 | out = self.relu(out) 90 | 91 | out = self.conv3(out) 92 | out = self.bn3(out) 93 | 94 | if self.downsample is not None: 95 | residual = self.downsample(x) 96 | 97 | out += residual 98 | out = self.relu(out) 99 | 100 | return out 101 | 102 | class FBResNet(nn.Module): 103 | 104 | def __init__(self, block, layers, num_classes=1000): 105 | self.inplanes = 64 106 | # Special attributs 107 | self.input_space = None 108 | self.input_size = (299, 299, 3) 109 | self.mean = None 110 | self.std = None 111 | super(FBResNet, self).__init__() 112 | # Modules 113 | self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, 114 | bias=True) 115 | self.bn1 = nn.BatchNorm2d(64) 116 | self.relu = nn.ReLU(inplace=True) 117 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 118 | self.layer1 = self._make_layer(block, 64, layers[0]) 119 | self.layer2 = self._make_layer(block, 128, layers[1], stride=2) 120 | self.layer3 = self._make_layer(block, 256, layers[2], stride=2) 121 | self.layer4 = self._make_layer(block, 512, layers[3], stride=2) 122 | self.avgpool = nn.AvgPool2d(7) 123 | self.last_linear = nn.Linear(512 * block.expansion, num_classes) 124 | 125 | for m in self.modules(): 126 | if isinstance(m, nn.Conv2d): 127 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 128 | m.weight.data.normal_(0, math.sqrt(2. / n)) 129 | elif isinstance(m, nn.BatchNorm2d): 130 | m.weight.data.fill_(1) 131 | m.bias.data.zero_() 132 | 133 | def _make_layer(self, block, planes, blocks, stride=1): 134 | downsample = None 135 | if stride != 1 or self.inplanes != planes * block.expansion: 136 | downsample = nn.Sequential( 137 | nn.Conv2d(self.inplanes, planes * block.expansion, 138 | kernel_size=1, stride=stride, bias=True), 139 | nn.BatchNorm2d(planes * block.expansion), 140 | ) 141 | 142 | layers = [] 143 | layers.append(block(self.inplanes, planes, stride, downsample)) 144 | self.inplanes = planes * block.expansion 145 | for i in range(1, blocks): 146 | layers.append(block(self.inplanes, planes)) 147 | 148 | return nn.Sequential(*layers) 149 | 150 | def features(self, input): 151 | x = self.conv1(input) 152 | self.conv1_input = x.clone() 153 | x = self.bn1(x) 154 | x = self.relu(x) 155 | x = self.maxpool(x) 156 | 157 | x = self.layer1(x) 158 | x = self.layer2(x) 159 | x = self.layer3(x) 160 | x = self.layer4(x) 161 | return x 162 | 163 | def logits(self, features): 164 | x = self.avgpool(features) 165 | x = x.view(x.size(0), -1) 166 | x = self.last_linear(x) 167 | return x 168 | 169 | def forward(self, input): 170 | x = self.features(input) 171 | x = self.logits(x) 172 | return x 173 | 174 | 175 | def fbresnet18(num_classes=1000): 176 | """Constructs a ResNet-18 model. 177 | 178 | Args: 179 | pretrained (bool): If True, returns a model pre-trained on ImageNet 180 | """ 181 | model = FBResNet(BasicBlock, [2, 2, 2, 2], num_classes=num_classes) 182 | return model 183 | 184 | 185 | def fbresnet34(num_classes=1000): 186 | """Constructs a ResNet-34 model. 187 | 188 | Args: 189 | pretrained (bool): If True, returns a model pre-trained on ImageNet 190 | """ 191 | model = FBResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes) 192 | return model 193 | 194 | 195 | def fbresnet50(num_classes=1000): 196 | """Constructs a ResNet-50 model. 197 | 198 | Args: 199 | pretrained (bool): If True, returns a model pre-trained on ImageNet 200 | """ 201 | model = FBResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes) 202 | return model 203 | 204 | 205 | def fbresnet101(num_classes=1000): 206 | """Constructs a ResNet-101 model. 207 | 208 | Args: 209 | pretrained (bool): If True, returns a model pre-trained on ImageNet 210 | """ 211 | model = FBResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes) 212 | return model 213 | 214 | 215 | def fbresnet152(num_classes=1000, pretrained='imagenet'): 216 | """Constructs a ResNet-152 model. 217 | 218 | Args: 219 | pretrained (bool): If True, returns a model pre-trained on ImageNet 220 | """ 221 | model = FBResNet(Bottleneck, [3, 8, 36, 3], num_classes=num_classes) 222 | if pretrained is not None: 223 | settings = pretrained_settings['fbresnet152'][pretrained] 224 | assert num_classes == settings['num_classes'], \ 225 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 226 | model.load_state_dict(model_zoo.load_url(settings['url'])) 227 | model.input_space = settings['input_space'] 228 | model.input_size = settings['input_size'] 229 | model.input_range = settings['input_range'] 230 | model.mean = settings['mean'] 231 | model.std = settings['std'] 232 | return model 233 | 234 | 235 | -------------------------------------------------------------------------------- /data/mnist.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import torch.utils.data as data 3 | from PIL import Image 4 | import os 5 | import os.path 6 | import errno 7 | import numpy as np 8 | import torch 9 | import codecs 10 | from .utils import noisify 11 | 12 | 13 | class MNIST(data.Dataset): 14 | """`MNIST `_ Dataset. 15 | 16 | Args: 17 | root (string): Root directory of dataset where ``processed/training.pt`` 18 | and ``processed/test.pt`` exist. 19 | train (bool, optional): If True, creates dataset from ``training.pt``, 20 | otherwise from ``test.pt``. 21 | download (bool, optional): If true, downloads the dataset from the internet and 22 | puts it in root directory. If dataset is already downloaded, it is not 23 | downloaded again. 24 | transform (callable, optional): A function/transform that takes in an PIL image 25 | and returns a transformed version. E.g, ``transforms.RandomCrop`` 26 | target_transform (callable, optional): A function/transform that takes in the 27 | target and transforms it. 28 | """ 29 | urls = [ 30 | 'http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz', 31 | 'http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz', 32 | 'http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz', 33 | 'http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz', 34 | ] 35 | raw_folder = 'raw' 36 | processed_folder = 'processed' 37 | training_file = 'training.pt' 38 | test_file = 'test.pt' 39 | 40 | def __init__(self, root, train=True, transform=None, target_transform=None, download=False, 41 | noise_type=None, noise_rate=0.2, random_state=0): 42 | self.root = os.path.expanduser(root) 43 | self.transform = transform 44 | self.target_transform = target_transform 45 | self.train = train # training set or test set 46 | self.dataset='mnist' 47 | self.noise_type=noise_type 48 | 49 | if download: 50 | self.download() 51 | 52 | if not self._check_exists(): 53 | raise RuntimeError('Dataset not found.' + 54 | ' You can use download=True to download it') 55 | 56 | if self.train: 57 | self.train_data, self.train_labels = torch.load( 58 | os.path.join(self.root, self.processed_folder, self.training_file)) 59 | 60 | if noise_type != 'clean': 61 | self.train_labels=np.asarray([[self.train_labels[i]] for i in range(len(self.train_labels))]) 62 | self.train_noisy_labels, self.actual_noise_rate = noisify(dataset=self.dataset, train_labels=self.train_labels, noise_type=noise_type, noise_rate=noise_rate, random_state=random_state) 63 | self.train_noisy_labels=[i[0] for i in self.train_noisy_labels] 64 | _train_labels=[i[0] for i in self.train_labels] 65 | self.noise_or_not = np.transpose(self.train_noisy_labels)==np.transpose(_train_labels) 66 | else: 67 | self.test_data, self.test_labels = torch.load( 68 | os.path.join(self.root, self.processed_folder, self.test_file)) 69 | 70 | def __getitem__(self, index): 71 | """ 72 | Args: 73 | index (int): Index 74 | 75 | Returns: 76 | tuple: (image, target) where target is index of the target class. 77 | """ 78 | if self.train: 79 | #if self.noise_type is not None: 80 | if self.noise_type != 'clean': 81 | img, target = self.train_data[index], self.train_noisy_labels[index] 82 | else: 83 | img, target = self.train_data[index], self.train_labels[index] 84 | else: 85 | img, target = self.test_data[index], self.test_labels[index] 86 | 87 | # doing this so that it is consistent with all other datasets 88 | # to return a PIL Image 89 | img = Image.fromarray(img.numpy(), mode='L') 90 | 91 | if self.transform is not None: 92 | img = self.transform(img) 93 | 94 | if self.target_transform is not None: 95 | target = self.target_transform(target) 96 | 97 | return img, target, index 98 | 99 | def __len__(self): 100 | if self.train: 101 | return len(self.train_data) 102 | else: 103 | return len(self.test_data) 104 | 105 | def _check_exists(self): 106 | return os.path.exists(os.path.join(self.root, self.processed_folder, self.training_file)) and \ 107 | os.path.exists(os.path.join(self.root, self.processed_folder, self.test_file)) 108 | 109 | def download(self): 110 | """Download the MNIST data if it doesn't exist in processed_folder already.""" 111 | from six.moves import urllib 112 | import gzip 113 | 114 | if self._check_exists(): 115 | return 116 | 117 | # download files 118 | try: 119 | os.makedirs(os.path.join(self.root, self.raw_folder)) 120 | os.makedirs(os.path.join(self.root, self.processed_folder)) 121 | except OSError as e: 122 | if e.errno == errno.EEXIST: 123 | pass 124 | else: 125 | raise 126 | 127 | for url in self.urls: 128 | print('Downloading ' + url) 129 | data = urllib.request.urlopen(url) 130 | filename = url.rpartition('/')[2] 131 | file_path = os.path.join(self.root, self.raw_folder, filename) 132 | with open(file_path, 'wb') as f: 133 | f.write(data.read()) 134 | with open(file_path.replace('.gz', ''), 'wb') as out_f, \ 135 | gzip.GzipFile(file_path) as zip_f: 136 | out_f.write(zip_f.read()) 137 | os.unlink(file_path) 138 | 139 | # process and save as torch files 140 | print('Processing...') 141 | 142 | training_set = ( 143 | read_image_file(os.path.join(self.root, self.raw_folder, 'train-images-idx3-ubyte')), 144 | read_label_file(os.path.join(self.root, self.raw_folder, 'train-labels-idx1-ubyte')) 145 | ) 146 | test_set = ( 147 | read_image_file(os.path.join(self.root, self.raw_folder, 't10k-images-idx3-ubyte')), 148 | read_label_file(os.path.join(self.root, self.raw_folder, 't10k-labels-idx1-ubyte')) 149 | ) 150 | with open(os.path.join(self.root, self.processed_folder, self.training_file), 'wb') as f: 151 | torch.save(training_set, f) 152 | with open(os.path.join(self.root, self.processed_folder, self.test_file), 'wb') as f: 153 | torch.save(test_set, f) 154 | 155 | print('Done!') 156 | 157 | def __repr__(self): 158 | fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' 159 | fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) 160 | tmp = 'train' if self.train is True else 'test' 161 | fmt_str += ' Split: {}\n'.format(tmp) 162 | fmt_str += ' Root Location: {}\n'.format(self.root) 163 | tmp = ' Transforms (if any): ' 164 | fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 165 | tmp = ' Target Transforms (if any): ' 166 | fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 167 | return fmt_str 168 | 169 | 170 | def get_int(b): 171 | return int(codecs.encode(b, 'hex'), 16) 172 | 173 | 174 | def read_label_file(path): 175 | with open(path, 'rb') as f: 176 | data = f.read() 177 | assert get_int(data[:4]) == 2049 178 | length = get_int(data[4:8]) 179 | parsed = np.frombuffer(data, dtype=np.uint8, offset=8) 180 | return torch.from_numpy(parsed).view(length).long() 181 | 182 | 183 | def read_image_file(path): 184 | with open(path, 'rb') as f: 185 | data = f.read() 186 | assert get_int(data[:4]) == 2051 187 | length = get_int(data[4:8]) 188 | num_rows = get_int(data[8:12]) 189 | num_cols = get_int(data[12:16]) 190 | images = [] 191 | parsed = np.frombuffer(data, dtype=np.uint8, offset=16) 192 | return torch.from_numpy(parsed).view(length, num_rows, num_cols) 193 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/xception.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ported to pytorch thanks to [tstandley](https://github.com/tstandley/Xception-PyTorch) 3 | 4 | @author: tstandley 5 | Adapted by cadene 6 | 7 | Creates an Xception Model as defined in: 8 | 9 | Francois Chollet 10 | Xception: Deep Learning with Depthwise Separable Convolutions 11 | https://arxiv.org/pdf/1610.02357.pdf 12 | 13 | This weights ported from the Keras implementation. Achieves the following performance on the validation set: 14 | 15 | Loss:0.9173 Prec@1:78.892 Prec@5:94.292 16 | 17 | REMEMBER to set your image size to 3x299x299 for both test and validation 18 | 19 | normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], 20 | std=[0.5, 0.5, 0.5]) 21 | 22 | The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299 23 | """ 24 | from __future__ import print_function, division, absolute_import 25 | import math 26 | import torch 27 | import torch.nn as nn 28 | import torch.nn.functional as F 29 | import torch.utils.model_zoo as model_zoo 30 | from torch.nn import init 31 | 32 | __all__ = ['xception'] 33 | 34 | pretrained_settings = { 35 | 'xception': { 36 | 'imagenet': { 37 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/xception-43020ad28.pth', 38 | 'input_space': 'RGB', 39 | 'input_size': [3, 299, 299], 40 | 'input_range': [0, 1], 41 | 'mean': [0.5, 0.5, 0.5], 42 | 'std': [0.5, 0.5, 0.5], 43 | 'num_classes': 1000, 44 | 'scale': 0.8975 # The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299 45 | } 46 | } 47 | } 48 | 49 | 50 | class SeparableConv2d(nn.Module): 51 | def __init__(self,in_channels,out_channels,kernel_size=1,stride=1,padding=0,dilation=1,bias=False): 52 | super(SeparableConv2d,self).__init__() 53 | 54 | self.conv1 = nn.Conv2d(in_channels,in_channels,kernel_size,stride,padding,dilation,groups=in_channels,bias=bias) 55 | self.pointwise = nn.Conv2d(in_channels,out_channels,1,1,0,1,1,bias=bias) 56 | 57 | def forward(self,x): 58 | x = self.conv1(x) 59 | x = self.pointwise(x) 60 | return x 61 | 62 | 63 | class Block(nn.Module): 64 | def __init__(self,in_filters,out_filters,reps,strides=1,start_with_relu=True,grow_first=True): 65 | super(Block, self).__init__() 66 | 67 | if out_filters != in_filters or strides!=1: 68 | self.skip = nn.Conv2d(in_filters,out_filters,1,stride=strides, bias=False) 69 | self.skipbn = nn.BatchNorm2d(out_filters) 70 | else: 71 | self.skip=None 72 | 73 | self.relu = nn.ReLU(inplace=True) 74 | rep=[] 75 | 76 | filters=in_filters 77 | if grow_first: 78 | rep.append(self.relu) 79 | rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=1,bias=False)) 80 | rep.append(nn.BatchNorm2d(out_filters)) 81 | filters = out_filters 82 | 83 | for i in range(reps-1): 84 | rep.append(self.relu) 85 | rep.append(SeparableConv2d(filters,filters,3,stride=1,padding=1,bias=False)) 86 | rep.append(nn.BatchNorm2d(filters)) 87 | 88 | if not grow_first: 89 | rep.append(self.relu) 90 | rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=1,bias=False)) 91 | rep.append(nn.BatchNorm2d(out_filters)) 92 | 93 | if not start_with_relu: 94 | rep = rep[1:] 95 | else: 96 | rep[0] = nn.ReLU(inplace=False) 97 | 98 | if strides != 1: 99 | rep.append(nn.MaxPool2d(3,strides,1)) 100 | self.rep = nn.Sequential(*rep) 101 | 102 | def forward(self,inp): 103 | x = self.rep(inp) 104 | 105 | if self.skip is not None: 106 | skip = self.skip(inp) 107 | skip = self.skipbn(skip) 108 | else: 109 | skip = inp 110 | 111 | x+=skip 112 | return x 113 | 114 | 115 | class Xception(nn.Module): 116 | """ 117 | Xception optimized for the ImageNet dataset, as specified in 118 | https://arxiv.org/pdf/1610.02357.pdf 119 | """ 120 | def __init__(self, num_classes=1000): 121 | """ Constructor 122 | Args: 123 | num_classes: number of classes 124 | """ 125 | super(Xception, self).__init__() 126 | self.num_classes = num_classes 127 | 128 | self.conv1 = nn.Conv2d(3, 32, 3,2, 0, bias=False) 129 | self.bn1 = nn.BatchNorm2d(32) 130 | self.relu = nn.ReLU(inplace=True) 131 | 132 | self.conv2 = nn.Conv2d(32,64,3,bias=False) 133 | self.bn2 = nn.BatchNorm2d(64) 134 | #do relu here 135 | 136 | self.block1=Block(64,128,2,2,start_with_relu=False,grow_first=True) 137 | self.block2=Block(128,256,2,2,start_with_relu=True,grow_first=True) 138 | self.block3=Block(256,728,2,2,start_with_relu=True,grow_first=True) 139 | 140 | self.block4=Block(728,728,3,1,start_with_relu=True,grow_first=True) 141 | self.block5=Block(728,728,3,1,start_with_relu=True,grow_first=True) 142 | self.block6=Block(728,728,3,1,start_with_relu=True,grow_first=True) 143 | self.block7=Block(728,728,3,1,start_with_relu=True,grow_first=True) 144 | 145 | self.block8=Block(728,728,3,1,start_with_relu=True,grow_first=True) 146 | self.block9=Block(728,728,3,1,start_with_relu=True,grow_first=True) 147 | self.block10=Block(728,728,3,1,start_with_relu=True,grow_first=True) 148 | self.block11=Block(728,728,3,1,start_with_relu=True,grow_first=True) 149 | 150 | self.block12=Block(728,1024,2,2,start_with_relu=True,grow_first=False) 151 | 152 | self.conv3 = SeparableConv2d(1024,1536,3,1,1) 153 | self.bn3 = nn.BatchNorm2d(1536) 154 | 155 | #do relu here 156 | self.conv4 = SeparableConv2d(1536,2048,3,1,1) 157 | self.bn4 = nn.BatchNorm2d(2048) 158 | 159 | self.fc = nn.Linear(2048, num_classes) 160 | 161 | # #------- init weights -------- 162 | # for m in self.modules(): 163 | # if isinstance(m, nn.Conv2d): 164 | # n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 165 | # m.weight.data.normal_(0, math.sqrt(2. / n)) 166 | # elif isinstance(m, nn.BatchNorm2d): 167 | # m.weight.data.fill_(1) 168 | # m.bias.data.zero_() 169 | # #----------------------------- 170 | 171 | def features(self, input): 172 | x = self.conv1(input) 173 | x = self.bn1(x) 174 | x = self.relu(x) 175 | 176 | x = self.conv2(x) 177 | x = self.bn2(x) 178 | x = self.relu(x) 179 | 180 | x = self.block1(x) 181 | x = self.block2(x) 182 | x = self.block3(x) 183 | x = self.block4(x) 184 | x = self.block5(x) 185 | x = self.block6(x) 186 | x = self.block7(x) 187 | x = self.block8(x) 188 | x = self.block9(x) 189 | x = self.block10(x) 190 | x = self.block11(x) 191 | x = self.block12(x) 192 | 193 | x = self.conv3(x) 194 | x = self.bn3(x) 195 | x = self.relu(x) 196 | 197 | x = self.conv4(x) 198 | x = self.bn4(x) 199 | return x 200 | 201 | def logits(self, features): 202 | x = self.relu(features) 203 | 204 | x = F.adaptive_avg_pool2d(x, (1, 1)) 205 | x = x.view(x.size(0), -1) 206 | x = self.last_linear(x) 207 | return x 208 | 209 | def forward(self, input): 210 | x = self.features(input) 211 | x = self.logits(x) 212 | return x 213 | 214 | 215 | def xception(num_classes=1000, pretrained='imagenet'): 216 | model = Xception(num_classes=num_classes) 217 | if pretrained: 218 | settings = pretrained_settings['xception'][pretrained] 219 | assert num_classes == settings['num_classes'], \ 220 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 221 | 222 | model = Xception(num_classes=num_classes) 223 | model.load_state_dict(model_zoo.load_url(settings['url'])) 224 | 225 | model.input_space = settings['input_space'] 226 | model.input_size = settings['input_size'] 227 | model.input_range = settings['input_range'] 228 | model.mean = settings['mean'] 229 | model.std = settings['std'] 230 | 231 | # TODO: ugly 232 | model.last_linear = model.fc 233 | del model.fc 234 | return model 235 | -------------------------------------------------------------------------------- /phase2/data.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import copy 4 | import numpy as np 5 | import torch 6 | import torchvision 7 | from PIL import Image 8 | 9 | from torch.utils.data import SubsetRandomSampler, Subset, Dataset 10 | from torchvision.transforms import transforms 11 | from sklearn.model_selection import StratifiedShuffleSplit 12 | from theconf import Config as C 13 | 14 | from archive import autoaug_policy, autoaug_paper_cifar10, fa_reduced_cifar10 15 | from augmentations import * 16 | from common import get_logger 17 | from samplers.stratified_sampler import StratifiedSampler 18 | from utils import noisify 19 | 20 | logger = get_logger('Unsupervised Data Augmentation') 21 | logger.setLevel(logging.INFO) 22 | 23 | class MyCIFAR10(torchvision.datasets.CIFAR10): 24 | def __getitem__(self, index): 25 | """ 26 | Args: 27 | index (int): Index 28 | 29 | Returns: 30 | tuple: (image, target) where target is index of the target class. 31 | """ 32 | 33 | img, target = self.data[index], self.targets[index] 34 | 35 | # doing this so that it is consistent with all other datasets 36 | # to return a PIL Image 37 | img = Image.fromarray(img) 38 | 39 | if self.transform is not None: 40 | img = self.transform(img) 41 | 42 | if self.target_transform is not None: 43 | target = self.target_transform(target) 44 | 45 | return img, target, index 46 | 47 | 48 | 49 | def get_dataloaders(dataset, batch, batch_unsup, dataroot, with_noise=True, random_state=0, unsup_idx=set()): 50 | if 'cifar' in dataset: 51 | transform_train = transforms.Compose([ 52 | transforms.RandomCrop(32, padding=4), 53 | transforms.RandomHorizontalFlip(), 54 | transforms.ToTensor(), 55 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 56 | ]) 57 | transform_valid = transforms.Compose([ 58 | transforms.RandomCrop(32, padding=4), 59 | transforms.RandomHorizontalFlip(), 60 | transforms.ToTensor(), 61 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 62 | ]) 63 | transform_test = transforms.Compose([ 64 | transforms.ToTensor(), 65 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 66 | ]) 67 | else: 68 | raise ValueError('dataset=%s' % dataset) 69 | 70 | autoaug = transforms.Compose([]) 71 | if isinstance(C.get()['aug'], list): 72 | logger.debug('augmentation provided.') 73 | autoaug.transforms.insert(0, Augmentation(C.get()['aug'])) 74 | else: 75 | logger.debug('augmentation: %s' % C.get()['aug']) 76 | if C.get()['aug'] == 'fa_reduced_cifar10': 77 | autoaug.transforms.insert(0, Augmentation(fa_reduced_cifar10())) 78 | elif C.get()['aug'] == 'autoaug_cifar10': 79 | autoaug.transforms.insert(0, Augmentation(autoaug_paper_cifar10())) 80 | elif C.get()['aug'] == 'autoaug_extend': 81 | autoaug.transforms.insert(0, Augmentation(autoaug_policy())) 82 | elif C.get()['aug'] == 'default': 83 | pass 84 | else: 85 | raise ValueError('not found augmentations. %s' % C.get()['aug']) 86 | transform_train.transforms.insert(0, autoaug) 87 | 88 | if C.get()['cutout'] > 0: 89 | transform_train.transforms.append(CutoutDefault(C.get()['cutout'])) 90 | 91 | if dataset in ['cifar10', 'cifar100']: 92 | if dataset == 'cifar10': 93 | total_trainset = torchvision.datasets.CIFAR10(root=dataroot, train=True, download=True, transform=transform_train) 94 | unsup_trainset = torchvision.datasets.CIFAR10(root=dataroot, train=True, download=True, transform=None) 95 | testset = torchvision.datasets.CIFAR10(root=dataroot, train=False, download=True, transform=transform_test) 96 | #nb_classes = 10 97 | elif dataset == 'cifar100': 98 | total_trainset = torchvision.datasets.CIFAR100(root=dataroot, train=True, download=True, transform=transform_train) 99 | unsup_trainset = torchvision.datasets.CIFAR100(root=dataroot, train=True, download=True, transform=None) 100 | testset = torchvision.datasets.CIFAR100(root=dataroot, train=False, download=True, transform=transform_test) 101 | #nb_classes = 100 102 | else: 103 | raise ValueError 104 | print('DEBUG:', len(total_trainset.targets)) 105 | 106 | if not with_noise: 107 | sss = StratifiedShuffleSplit(n_splits=1, test_size=46000, random_state=0) # 4000 trainset 108 | sss = sss.split(list(range(len(total_trainset))), total_trainset.targets) 109 | train_idx, valid_idx = next(sss) 110 | #train_labels = [total_trainset.targets[idx] for idx in train_idx] 111 | 112 | trainset = Subset(total_trainset, train_idx) # for supervised 113 | #trainset.targets = train_labels #THIS DOES NOTHING 114 | 115 | otherset = Subset(unsup_trainset, valid_idx) # for unsupervised 116 | # otherset = unsup_trainset 117 | otherset = UnsupervisedDataset(otherset, transform_valid, autoaug, cutout=C.get()['cutout']) 118 | else: 119 | #import ipdb 120 | #ipdb.set_trace() 121 | 122 | #print('Noisy data config: noise_rate={}, noise_type={}'.format(noise_rate, noise_type)) 123 | print('unsup_idx:', len(unsup_idx)) 124 | 125 | all_idx = list(range(len(total_trainset))) 126 | sup_idx = [idx for idx in all_idx if idx not in unsup_idx] 127 | print('sup_idx: ', len(sup_idx)) 128 | 129 | #apply noise to supervised trainset 130 | train_labels_with_noise = np.load(C.get()['train_labels']).reshape(-1) 131 | noisy_trainset = copy.deepcopy(total_trainset) 132 | noisy_trainset.targets = train_labels_with_noise 133 | 134 | train_labels_clean = np.array(total_trainset.targets) 135 | sup_labels_clean = np.array([train_labels_clean[idx] for idx in sup_idx]) #for estimating actual noise rate 136 | 137 | est_noise = len(np.where(train_labels_clean!=train_labels_with_noise)[0]) 138 | print('noise labels total: ', est_noise) 139 | print('estimated noise rate: ', est_noise / len(train_labels_clean)) 140 | 141 | trainset = Subset(noisy_trainset, sup_idx) 142 | otherset = Subset(unsup_trainset, unsup_idx) 143 | 144 | sup_labels_with_noise = [trainset.dataset.targets[idx] for idx in sup_idx] 145 | est_noise = len(np.where(sup_labels_clean != np.array(sup_labels_with_noise))[0]) 146 | print('noise labels in sup. data: ', est_noise) 147 | print('sup. data noise rate: ', est_noise / len(sup_labels_clean)) 148 | 149 | trainset.targets = sup_labels_with_noise #only for sampler 150 | otherset = UnsupervisedDataset(otherset, transform_valid, autoaug, cutout=C.get()['cutout']) 151 | else: 152 | raise ValueError('invalid dataset name=%s' % dataset) 153 | 154 | trainloader = torch.utils.data.DataLoader( 155 | trainset, batch_size=batch, shuffle=False, num_workers=8, pin_memory=False, 156 | sampler=StratifiedSampler(trainset.targets), drop_last=True) 157 | 158 | unsuploader = torch.utils.data.DataLoader( 159 | otherset, batch_size=batch_unsup, shuffle=True, num_workers=8, pin_memory=False, 160 | sampler=None, drop_last=True) 161 | 162 | testloader = torch.utils.data.DataLoader( 163 | testset, batch_size=batch, shuffle=False, num_workers=32, pin_memory=False, 164 | drop_last=False 165 | ) 166 | return trainloader, unsuploader, testloader 167 | 168 | 169 | class CutoutDefault(object): 170 | """ 171 | Reference : https://github.com/quark0/darts/blob/master/cnn/utils.py 172 | """ 173 | def __init__(self, length): 174 | self.length = length 175 | 176 | def __call__(self, img): 177 | if self.length <= 0: 178 | return img 179 | h, w = img.size(1), img.size(2) 180 | mask = np.ones((h, w), np.float32) 181 | y = np.random.randint(h) 182 | x = np.random.randint(w) 183 | 184 | y1 = np.clip(y - self.length // 2, 0, h) 185 | y2 = np.clip(y + self.length // 2, 0, h) 186 | x1 = np.clip(x - self.length // 2, 0, w) 187 | x2 = np.clip(x + self.length // 2, 0, w) 188 | 189 | mask[y1: y2, x1: x2] = 0. 190 | mask = torch.from_numpy(mask) 191 | mask = mask.expand_as(img) 192 | img *= mask 193 | return img 194 | 195 | 196 | class Augmentation(object): 197 | def __init__(self, policies): 198 | self.policies = policies 199 | 200 | def __call__(self, img): 201 | for _ in range(1): 202 | policy = random.choice(self.policies) 203 | for name, pr, level in policy: 204 | if random.random() > pr: 205 | continue 206 | img = apply_augment(img, name, level) 207 | return img 208 | 209 | 210 | class UnsupervisedDataset(Dataset): 211 | def __init__(self, dataset, transform_default, transform_aug, cutout=0): 212 | self.dataset = dataset 213 | self.transform_default = transform_default 214 | self.transform_aug = transform_aug 215 | self.transform_cutout = CutoutDefault(cutout) # issue 4 : https://github.com/ildoonet/unsupervised-data-augmentation/issues/4 216 | 217 | def __getitem__(self, index): 218 | img, _ = self.dataset[index] 219 | 220 | img1 = self.transform_default(img) 221 | img2 = self.transform_default(self.transform_aug(img)) 222 | img2 = self.transform_cutout(img2) 223 | 224 | return img1, img2 225 | 226 | def __len__(self): 227 | return len(self.dataset) 228 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/datasets/voc.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import csv 3 | import os 4 | import os.path 5 | import tarfile 6 | from six.moves.urllib.parse import urlparse 7 | 8 | import numpy as np 9 | import torch 10 | import torch.utils.data as data 11 | from PIL import Image 12 | 13 | from . import utils 14 | 15 | object_categories = ['aeroplane', 'bicycle', 'bird', 'boat', 16 | 'bottle', 'bus', 'car', 'cat', 'chair', 17 | 'cow', 'diningtable', 'dog', 'horse', 18 | 'motorbike', 'person', 'pottedplant', 19 | 'sheep', 'sofa', 'train', 'tvmonitor'] 20 | 21 | urls = { 22 | 'devkit': 'http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCdevkit_18-May-2011.tar', 23 | 'trainval_2007': 'http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar', 24 | 'test_images_2007': 'http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar', 25 | 'test_anno_2007': 'http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtestnoimgs_06-Nov-2007.tar', 26 | } 27 | 28 | 29 | def read_image_label(file): 30 | print('[dataset] read ' + file) 31 | data = dict() 32 | with open(file, 'r') as f: 33 | for line in f: 34 | tmp = line.split(' ') 35 | name = tmp[0] 36 | label = int(tmp[-1]) 37 | data[name] = label 38 | # data.append([name, label]) 39 | # print('%s %d' % (name, label)) 40 | return data 41 | 42 | 43 | def read_object_labels(root, dataset, set): 44 | path_labels = os.path.join(root, 'VOCdevkit', dataset, 'ImageSets', 'Main') 45 | labeled_data = dict() 46 | num_classes = len(object_categories) 47 | 48 | for i in range(num_classes): 49 | file = os.path.join(path_labels, object_categories[i] + '_' + set + '.txt') 50 | data = read_image_label(file) 51 | 52 | if i == 0: 53 | for (name, label) in data.items(): 54 | labels = np.zeros(num_classes) 55 | labels[i] = label 56 | labeled_data[name] = labels 57 | else: 58 | for (name, label) in data.items(): 59 | labeled_data[name][i] = label 60 | 61 | return labeled_data 62 | 63 | 64 | def write_object_labels_csv(file, labeled_data): 65 | # write a csv file 66 | print('[dataset] write file %s' % file) 67 | with open(file, 'w') as csvfile: 68 | fieldnames = ['name'] 69 | fieldnames.extend(object_categories) 70 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 71 | 72 | writer.writeheader() 73 | for (name, labels) in labeled_data.items(): 74 | example = {'name': name} 75 | for i in range(20): 76 | example[fieldnames[i + 1]] = int(labels[i]) 77 | writer.writerow(example) 78 | 79 | csvfile.close() 80 | 81 | 82 | def read_object_labels_csv(file, header=True): 83 | images = [] 84 | num_categories = 0 85 | print('[dataset] read', file) 86 | with open(file, 'r') as f: 87 | reader = csv.reader(f) 88 | rownum = 0 89 | for row in reader: 90 | if header and rownum == 0: 91 | header = row 92 | else: 93 | if num_categories == 0: 94 | num_categories = len(row) - 1 95 | name = row[0] 96 | labels = (np.asarray(row[1:num_categories + 1])).astype(np.float32) 97 | labels = torch.from_numpy(labels) 98 | item = (name, labels) 99 | images.append(item) 100 | rownum += 1 101 | return images 102 | 103 | 104 | def find_images_classification(root, dataset, set): 105 | path_labels = os.path.join(root, 'VOCdevkit', dataset, 'ImageSets', 'Main') 106 | images = [] 107 | file = os.path.join(path_labels, set + '.txt') 108 | with open(file, 'r') as f: 109 | for line in f: 110 | images.append(line) 111 | return images 112 | 113 | 114 | def download_voc2007(root): 115 | path_devkit = os.path.join(root, 'VOCdevkit') 116 | path_images = os.path.join(root, 'VOCdevkit', 'VOC2007', 'JPEGImages') 117 | tmpdir = os.path.join(root, 'tmp') 118 | 119 | # create directory 120 | if not os.path.exists(root): 121 | os.makedirs(root) 122 | 123 | if not os.path.exists(path_devkit): 124 | 125 | if not os.path.exists(tmpdir): 126 | os.makedirs(tmpdir) 127 | 128 | parts = urlparse(urls['devkit']) 129 | filename = os.path.basename(parts.path) 130 | cached_file = os.path.join(tmpdir, filename) 131 | 132 | if not os.path.exists(cached_file): 133 | print('Downloading: "{}" to {}\n'.format(urls['devkit'], cached_file)) 134 | utils.download_url(urls['devkit'], cached_file) 135 | 136 | # extract file 137 | print('[dataset] Extracting tar file {file} to {path}'.format(file=cached_file, path=root)) 138 | cwd = os.getcwd() 139 | tar = tarfile.open(cached_file, "r") 140 | os.chdir(root) 141 | tar.extractall() 142 | tar.close() 143 | os.chdir(cwd) 144 | print('[dataset] Done!') 145 | 146 | # train/val images/annotations 147 | if not os.path.exists(path_images): 148 | 149 | # download train/val images/annotations 150 | parts = urlparse(urls['trainval_2007']) 151 | filename = os.path.basename(parts.path) 152 | cached_file = os.path.join(tmpdir, filename) 153 | 154 | if not os.path.exists(cached_file): 155 | print('Downloading: "{}" to {}\n'.format(urls['trainval_2007'], cached_file)) 156 | utils.download_url(urls['trainval_2007'], cached_file) 157 | 158 | # extract file 159 | print('[dataset] Extracting tar file {file} to {path}'.format(file=cached_file, path=root)) 160 | cwd = os.getcwd() 161 | tar = tarfile.open(cached_file, "r") 162 | os.chdir(root) 163 | tar.extractall() 164 | tar.close() 165 | os.chdir(cwd) 166 | print('[dataset] Done!') 167 | 168 | # test annotations 169 | test_anno = os.path.join(path_devkit, 'VOC2007/ImageSets/Main/aeroplane_test.txt') 170 | if not os.path.exists(test_anno): 171 | 172 | # download test annotations 173 | parts = urlparse(urls['test_images_2007']) 174 | filename = os.path.basename(parts.path) 175 | cached_file = os.path.join(tmpdir, filename) 176 | 177 | if not os.path.exists(cached_file): 178 | print('Downloading: "{}" to {}\n'.format(urls['test_images_2007'], cached_file)) 179 | utils.download_url(urls['test_images_2007'], cached_file) 180 | 181 | # extract file 182 | print('[dataset] Extracting tar file {file} to {path}'.format(file=cached_file, path=root)) 183 | cwd = os.getcwd() 184 | tar = tarfile.open(cached_file, "r") 185 | os.chdir(root) 186 | tar.extractall() 187 | tar.close() 188 | os.chdir(cwd) 189 | print('[dataset] Done!') 190 | 191 | # test images 192 | test_image = os.path.join(path_devkit, 'VOC2007/JPEGImages/000001.jpg') 193 | if not os.path.exists(test_image): 194 | 195 | # download test images 196 | parts = urlparse(urls['test_anno_2007']) 197 | filename = os.path.basename(parts.path) 198 | cached_file = os.path.join(tmpdir, filename) 199 | 200 | if not os.path.exists(cached_file): 201 | print('Downloading: "{}" to {}\n'.format(urls['test_anno_2007'], cached_file)) 202 | utils.download_url(urls['test_anno_2007'], cached_file) 203 | 204 | # extract file 205 | print('[dataset] Extracting tar file {file} to {path}'.format(file=cached_file, path=root)) 206 | cwd = os.getcwd() 207 | tar = tarfile.open(cached_file, "r") 208 | os.chdir(root) 209 | tar.extractall() 210 | tar.close() 211 | os.chdir(cwd) 212 | print('[dataset] Done!') 213 | 214 | 215 | class Voc2007Classification(data.Dataset): 216 | 217 | def __init__(self, root, set, transform=None, target_transform=None): 218 | self.root = root 219 | self.path_devkit = os.path.join(root, 'VOCdevkit') 220 | self.path_images = os.path.join(root, 'VOCdevkit', 'VOC2007', 'JPEGImages') 221 | self.set = set 222 | self.transform = transform 223 | self.target_transform = target_transform 224 | 225 | # download dataset 226 | download_voc2007(self.root) 227 | 228 | # define path of csv file 229 | path_csv = os.path.join(self.root, 'files', 'VOC2007') 230 | # define filename of csv file 231 | file_csv = os.path.join(path_csv, 'classification_' + set + '.csv') 232 | 233 | # create the csv file if necessary 234 | if not os.path.exists(file_csv): 235 | if not os.path.exists(path_csv): # create dir if necessary 236 | os.makedirs(path_csv) 237 | # generate csv file 238 | labeled_data = read_object_labels(self.root, 'VOC2007', self.set) 239 | # write csv file 240 | write_object_labels_csv(file_csv, labeled_data) 241 | 242 | self.classes = object_categories 243 | self.images = read_object_labels_csv(file_csv) 244 | 245 | print('[dataset] VOC 2007 classification set=%s number of classes=%d number of images=%d' % ( 246 | set, len(self.classes), len(self.images))) 247 | 248 | def __getitem__(self, index): 249 | path, target = self.images[index] 250 | img = Image.open(os.path.join(self.path_images, path + '.jpg')).convert('RGB') 251 | if self.transform is not None: 252 | img = self.transform(img) 253 | if self.target_transform is not None: 254 | target = self.target_transform(target) 255 | return img, path, target 256 | 257 | def __len__(self): 258 | return len(self.images) 259 | 260 | def get_number_classes(self): 261 | return len(self.classes) 262 | -------------------------------------------------------------------------------- /phase1.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import os 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | from torch.autograd import Variable 7 | import torchvision.transforms as transforms 8 | from data.cifar import CIFAR10, CIFAR100 9 | from data.mnist import MNIST 10 | from data.datasets import input_dataset 11 | from models import * 12 | import argparse, sys 13 | import numpy as np 14 | import datetime 15 | import shutil 16 | from random import sample 17 | from loss import loss_cross_entropy,loss_cores,f_beta 18 | 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('--lr', type = float, default = 0.05) 21 | parser.add_argument('--lr_plan', type = str, help = 'base, cyclic', default = 'cyclic') 22 | parser.add_argument('--loss', type = str, help = 'ce, cores', default = 'cores') 23 | parser.add_argument('--result_dir', type = str, help = 'dir to save result txt files', default = 'results') 24 | parser.add_argument('--noise_rate', type = float, help = 'corruption rate, should be less than 1', default = 0.2) 25 | parser.add_argument('--noise_type', type = str, help='[pairflip, symmetric,instance]', default='pairflip') 26 | parser.add_argument('--top_bn', action='store_true') 27 | parser.add_argument('--ideal', action='store_true') 28 | parser.add_argument('--dataset', type = str, help = 'mnist, cifar10, or cifar100', default = 'cifar10') 29 | parser.add_argument('--model', type = str, help = 'cnn,resnet', default = 'cnn') 30 | parser.add_argument('--n_epoch', type=int, default=100) 31 | parser.add_argument('--seed', type=int, default=0) 32 | parser.add_argument('--print_freq', type=int, default=50) 33 | parser.add_argument('--num_workers', type=int, default=4, help='how many subprocesses to use for data loading') 34 | parser.add_argument('--resume', '-r', action='store_true', help='resume from checkpoint') 35 | 36 | def get_noise_pred(loss_div, args, epoch=-1, alpha=0.): 37 | #Get noise prediction 38 | print('DEBUG, loss_div', loss_div.shape) 39 | llast = loss_div[:, epoch] 40 | idx_last = np.where(llast>alpha)[0] 41 | print('last idx:', idx_last.shape) 42 | return idx_last 43 | 44 | # Adjust learning rate and for SGD Optimizer 45 | def adjust_learning_rate(optimizer, epoch,alpha_plan): 46 | for param_group in optimizer.param_groups: 47 | param_group['lr']=alpha_plan[epoch]/(1+f_beta(epoch)) 48 | 49 | 50 | def accuracy(logit, target, topk=(1,)): 51 | """Computes the precision@k for the specified values of k""" 52 | output = F.softmax(logit, dim=1) 53 | maxk = max(topk) 54 | batch_size = target.size(0) 55 | 56 | _, pred = output.topk(maxk, 1, True, True) 57 | pred = pred.t() 58 | correct = pred.eq(target.view(1, -1).expand_as(pred)) 59 | 60 | res = [] 61 | for k in topk: 62 | correct_k = correct[:k].view(-1).float().sum(0, keepdim=True) 63 | res.append(correct_k.mul_(100.0 / batch_size)) 64 | return res 65 | 66 | # Train the Model 67 | def train(epoch, num_classes, train_loader,model, optimizer,loss_all,loss_div_all,loss_type, noise_prior = None): 68 | train_total=0 69 | train_correct=0 70 | print(f'current beta is {f_beta(epoch)}') 71 | v_list = np.zeros(num_training_samples) 72 | idx_each_class_noisy = [[] for i in range(num_classes)] 73 | if not isinstance(noise_prior, torch.Tensor): 74 | noise_prior = torch.tensor(noise_prior.astype('float32')).cuda().unsqueeze(0) 75 | for i, (images, labels, indexes) in enumerate(train_loader): 76 | ind=indexes.cpu().numpy().transpose() 77 | batch_size = len(ind) 78 | class_list = range(num_classes) 79 | 80 | images = Variable(images).cuda() 81 | labels = Variable(labels).cuda() 82 | 83 | # Forward + Backward + Optimize 84 | logits = model(images) 85 | prec, _ = accuracy(logits, labels, topk=(1, 5)) 86 | train_total+=1 87 | train_correct+=prec 88 | if loss_type=='ce': 89 | loss = loss_cross_entropy(epoch,logits, labels,class_list,ind, noise_or_not, loss_all, loss_div_all) 90 | elif loss_type=='cores': 91 | loss, loss_v = loss_cores(epoch,logits, labels,class_list,ind, noise_or_not, loss_all, loss_div_all, noise_prior = noise_prior) 92 | v_list[ind] = loss_v 93 | for i in range(batch_size): 94 | if loss_v[i] == 0: 95 | idx_each_class_noisy[labels[i]].append(ind[i]) 96 | else: 97 | print('loss type not supported') 98 | raise SystemExit 99 | optimizer.zero_grad() 100 | loss.backward() 101 | optimizer.step() 102 | if (i+1) % args.print_freq == 0: 103 | print ('Epoch [%d/%d], Iter [%d/%d] Training Accuracy: %.4F, Loss: %.4f' 104 | %(epoch+1, args.n_epoch, i+1, len(train_dataset)//batch_size, prec, loss.data)) 105 | 106 | class_size_noisy = [len(idx_each_class_noisy[i]) for i in range(num_classes)] 107 | noise_prior_delta = np.array(class_size_noisy) 108 | print(noise_prior_delta) 109 | 110 | train_acc=float(train_correct)/float(train_total) 111 | return train_acc, noise_prior_delta 112 | 113 | # Evaluate the Model 114 | def evaluate(test_loader,model,save=False,epoch=0,best_acc_=0,args=None): 115 | model.eval() # Change model to 'eval' mode. 116 | print('previous_best', best_acc_) 117 | correct = 0 118 | total = 0 119 | for images, labels, _ in test_loader: 120 | images = Variable(images).cuda() 121 | logits = model(images) 122 | outputs = F.softmax(logits, dim=1) 123 | _, pred = torch.max(outputs.data, 1) 124 | total += labels.size(0) 125 | correct += (pred.cpu() == labels).sum() 126 | acc = 100*float(correct)/float(total) 127 | 128 | if save: 129 | if acc > best_acc_: 130 | state = {'state_dict': model.state_dict(), 131 | 'epoch':epoch, 132 | 'acc':acc, 133 | } 134 | torch.save(state,os.path.join(save_dir,args.loss + args.noise_type + str(args.noise_rate)+'best.pth.tar')) 135 | #np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'loss_div_all_best.npy',loss_div_all) 136 | #np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'loss_all_best.npy',loss_all) 137 | best_acc_ = acc 138 | if epoch == args.n_epoch -1: 139 | state = {'state_dict': model.state_dict(), 140 | 'epoch':epoch, 141 | 'acc':acc, 142 | } 143 | torch.save(state,os.path.join(save_dir,args.loss + args.noise_type + str(args.noise_rate)+'last.pth.tar')) 144 | #np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'loss_div_all_last.npy',loss_div_all) 145 | #np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'loss_all_best.npy',loss_all) 146 | return acc, best_acc_ 147 | 148 | 149 | 150 | #####################################main code ################################################ 151 | args = parser.parse_args() 152 | # Seed 153 | torch.manual_seed(args.seed) 154 | torch.cuda.manual_seed(args.seed) 155 | 156 | # Hyper Parameters 157 | batch_size = 64 158 | learning_rate = args.lr 159 | 160 | # load dataset 161 | train_dataset,test_dataset,num_classes,num_training_samples = input_dataset(args.dataset,args.noise_type,args.noise_rate) 162 | noise_prior = train_dataset.noise_prior 163 | noise_or_not = train_dataset.noise_or_not 164 | print('train_labels:', len(train_dataset.train_labels), train_dataset.train_labels[:10]) 165 | # load model 166 | print('building model...') 167 | if args.model == 'cnn': 168 | model = CNN(input_channel=3, n_outputs=num_classes) 169 | else: 170 | model = ResNet34(num_classes) 171 | print('building model done') 172 | optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) 173 | # Creat loss and loss_div for each sample at each epoch 174 | loss_all = np.zeros((num_training_samples,args.n_epoch)) 175 | loss_div_all = np.zeros((num_training_samples,args.n_epoch)) 176 | ### save result and model checkpoint ####### 177 | save_dir = args.result_dir +'/' +args.dataset + '/' + args.model 178 | if not os.path.exists(save_dir): 179 | os.system('mkdir -p %s' % save_dir) 180 | train_loader = torch.utils.data.DataLoader(dataset = train_dataset, 181 | batch_size = batch_size, 182 | num_workers=args.num_workers, 183 | shuffle=True) 184 | 185 | test_loader = torch.utils.data.DataLoader(dataset=test_dataset, 186 | batch_size = 64, 187 | num_workers=args.num_workers, 188 | shuffle=False) 189 | alpha_plan = [0.1] * 50 + [0.01] * 50 190 | #alpha_plan = [] 191 | #for ii in range(args.n_epoch): 192 | # alpha_plan.append(learning_rate*pow(0.95,ii)) 193 | model.cuda() 194 | txtfile=save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate) + '.txt' 195 | if os.path.exists(txtfile): 196 | os.system('rm %s' % txtfile) 197 | with open(txtfile, "a") as myfile: 198 | myfile.write('epoch: train_acc test_acc \n') 199 | 200 | epoch=0 201 | train_acc = 0 202 | best_acc_ = 0.0 203 | #print(best_acc_) 204 | # training 205 | noise_prior_cur = noise_prior 206 | for epoch in range(args.n_epoch): 207 | # train models 208 | adjust_learning_rate(optimizer, epoch, alpha_plan) 209 | model.train() 210 | train_acc, noise_prior_delta = train(epoch,num_classes,train_loader, model, optimizer,loss_all,loss_div_all,args.loss,noise_prior = noise_prior_cur) 211 | noise_prior_cur = noise_prior*num_training_samples - noise_prior_delta 212 | noise_prior_cur = noise_prior_cur/sum(noise_prior_cur) 213 | # evaluate models 214 | test_acc, best_acc_ = evaluate(test_loader=test_loader, save=True, model=model,epoch=epoch,best_acc_=best_acc_,args=args) 215 | # save results 216 | #det_by_loss = det_acc(save_dir,best_ratio,args,loss_all,noise_or_not,epoch,sum_epoch = False) 217 | #det_by_loss_div = det_acc(save_dir,best_ratio,args,loss_div_all,noise_or_not,epoch,sum_epoch = False) 218 | print('train acc on train images is ', train_acc) 219 | print('test acc on test images is ', test_acc) 220 | #print('precision of labels by loss is', det_by_loss) 221 | #print('precision of labels by loss div is', det_by_loss_div) 222 | with open(txtfile, "a") as myfile: 223 | myfile.write(str(int(epoch)) + ': ' + str(train_acc) +' ' + str(test_acc) + "\n") 224 | np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'loss_all.npy',loss_all) 225 | np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'loss_div_all.npy',loss_div_all) 226 | np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'noise_or_not.npy',noise_or_not) 227 | np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'train_noisy_labels.npy',train_dataset.train_noisy_labels) 228 | if epoch ==40: 229 | idx_last = get_noise_pred(loss_div_all, args, epoch=epoch) 230 | np.save(save_dir + '/' + args.loss + args.noise_type + str(args.noise_rate)+'_noise_pred.npy',idx_last) 231 | -------------------------------------------------------------------------------- /phase2/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/inceptionv4.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import torch 3 | import torch.nn as nn 4 | import torch.utils.model_zoo as model_zoo 5 | import os 6 | import sys 7 | 8 | __all__ = ['InceptionV4', 'inceptionv4'] 9 | 10 | pretrained_settings = { 11 | 'inceptionv4': { 12 | 'imagenet': { 13 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionv4-8e4777a0.pth', 14 | 'input_space': 'RGB', 15 | 'input_size': [3, 299, 299], 16 | 'input_range': [0, 1], 17 | 'mean': [0.5, 0.5, 0.5], 18 | 'std': [0.5, 0.5, 0.5], 19 | 'num_classes': 1000 20 | }, 21 | 'imagenet+background': { 22 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionv4-8e4777a0.pth', 23 | 'input_space': 'RGB', 24 | 'input_size': [3, 299, 299], 25 | 'input_range': [0, 1], 26 | 'mean': [0.5, 0.5, 0.5], 27 | 'std': [0.5, 0.5, 0.5], 28 | 'num_classes': 1001 29 | } 30 | } 31 | } 32 | 33 | 34 | class BasicConv2d(nn.Module): 35 | 36 | def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0): 37 | super(BasicConv2d, self).__init__() 38 | self.conv = nn.Conv2d(in_planes, out_planes, 39 | kernel_size=kernel_size, stride=stride, 40 | padding=padding, bias=False) # verify bias false 41 | self.bn = nn.BatchNorm2d(out_planes, 42 | eps=0.001, # value found in tensorflow 43 | momentum=0.1, # default pytorch value 44 | affine=True) 45 | self.relu = nn.ReLU(inplace=True) 46 | 47 | def forward(self, x): 48 | x = self.conv(x) 49 | x = self.bn(x) 50 | x = self.relu(x) 51 | return x 52 | 53 | 54 | class Mixed_3a(nn.Module): 55 | 56 | def __init__(self): 57 | super(Mixed_3a, self).__init__() 58 | self.maxpool = nn.MaxPool2d(3, stride=2) 59 | self.conv = BasicConv2d(64, 96, kernel_size=3, stride=2) 60 | 61 | def forward(self, x): 62 | x0 = self.maxpool(x) 63 | x1 = self.conv(x) 64 | out = torch.cat((x0, x1), 1) 65 | return out 66 | 67 | 68 | class Mixed_4a(nn.Module): 69 | 70 | def __init__(self): 71 | super(Mixed_4a, self).__init__() 72 | 73 | self.branch0 = nn.Sequential( 74 | BasicConv2d(160, 64, kernel_size=1, stride=1), 75 | BasicConv2d(64, 96, kernel_size=3, stride=1) 76 | ) 77 | 78 | self.branch1 = nn.Sequential( 79 | BasicConv2d(160, 64, kernel_size=1, stride=1), 80 | BasicConv2d(64, 64, kernel_size=(1,7), stride=1, padding=(0,3)), 81 | BasicConv2d(64, 64, kernel_size=(7,1), stride=1, padding=(3,0)), 82 | BasicConv2d(64, 96, kernel_size=(3,3), stride=1) 83 | ) 84 | 85 | def forward(self, x): 86 | x0 = self.branch0(x) 87 | x1 = self.branch1(x) 88 | out = torch.cat((x0, x1), 1) 89 | return out 90 | 91 | 92 | class Mixed_5a(nn.Module): 93 | 94 | def __init__(self): 95 | super(Mixed_5a, self).__init__() 96 | self.conv = BasicConv2d(192, 192, kernel_size=3, stride=2) 97 | self.maxpool = nn.MaxPool2d(3, stride=2) 98 | 99 | def forward(self, x): 100 | x0 = self.conv(x) 101 | x1 = self.maxpool(x) 102 | out = torch.cat((x0, x1), 1) 103 | return out 104 | 105 | 106 | class Inception_A(nn.Module): 107 | 108 | def __init__(self): 109 | super(Inception_A, self).__init__() 110 | self.branch0 = BasicConv2d(384, 96, kernel_size=1, stride=1) 111 | 112 | self.branch1 = nn.Sequential( 113 | BasicConv2d(384, 64, kernel_size=1, stride=1), 114 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1) 115 | ) 116 | 117 | self.branch2 = nn.Sequential( 118 | BasicConv2d(384, 64, kernel_size=1, stride=1), 119 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1), 120 | BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1) 121 | ) 122 | 123 | self.branch3 = nn.Sequential( 124 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 125 | BasicConv2d(384, 96, kernel_size=1, stride=1) 126 | ) 127 | 128 | def forward(self, x): 129 | x0 = self.branch0(x) 130 | x1 = self.branch1(x) 131 | x2 = self.branch2(x) 132 | x3 = self.branch3(x) 133 | out = torch.cat((x0, x1, x2, x3), 1) 134 | return out 135 | 136 | 137 | class Reduction_A(nn.Module): 138 | 139 | def __init__(self): 140 | super(Reduction_A, self).__init__() 141 | self.branch0 = BasicConv2d(384, 384, kernel_size=3, stride=2) 142 | 143 | self.branch1 = nn.Sequential( 144 | BasicConv2d(384, 192, kernel_size=1, stride=1), 145 | BasicConv2d(192, 224, kernel_size=3, stride=1, padding=1), 146 | BasicConv2d(224, 256, kernel_size=3, stride=2) 147 | ) 148 | 149 | self.branch2 = nn.MaxPool2d(3, stride=2) 150 | 151 | def forward(self, x): 152 | x0 = self.branch0(x) 153 | x1 = self.branch1(x) 154 | x2 = self.branch2(x) 155 | out = torch.cat((x0, x1, x2), 1) 156 | return out 157 | 158 | 159 | class Inception_B(nn.Module): 160 | 161 | def __init__(self): 162 | super(Inception_B, self).__init__() 163 | self.branch0 = BasicConv2d(1024, 384, kernel_size=1, stride=1) 164 | 165 | self.branch1 = nn.Sequential( 166 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 167 | BasicConv2d(192, 224, kernel_size=(1,7), stride=1, padding=(0,3)), 168 | BasicConv2d(224, 256, kernel_size=(7,1), stride=1, padding=(3,0)) 169 | ) 170 | 171 | self.branch2 = nn.Sequential( 172 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 173 | BasicConv2d(192, 192, kernel_size=(7,1), stride=1, padding=(3,0)), 174 | BasicConv2d(192, 224, kernel_size=(1,7), stride=1, padding=(0,3)), 175 | BasicConv2d(224, 224, kernel_size=(7,1), stride=1, padding=(3,0)), 176 | BasicConv2d(224, 256, kernel_size=(1,7), stride=1, padding=(0,3)) 177 | ) 178 | 179 | self.branch3 = nn.Sequential( 180 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 181 | BasicConv2d(1024, 128, kernel_size=1, stride=1) 182 | ) 183 | 184 | def forward(self, x): 185 | x0 = self.branch0(x) 186 | x1 = self.branch1(x) 187 | x2 = self.branch2(x) 188 | x3 = self.branch3(x) 189 | out = torch.cat((x0, x1, x2, x3), 1) 190 | return out 191 | 192 | 193 | class Reduction_B(nn.Module): 194 | 195 | def __init__(self): 196 | super(Reduction_B, self).__init__() 197 | 198 | self.branch0 = nn.Sequential( 199 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 200 | BasicConv2d(192, 192, kernel_size=3, stride=2) 201 | ) 202 | 203 | self.branch1 = nn.Sequential( 204 | BasicConv2d(1024, 256, kernel_size=1, stride=1), 205 | BasicConv2d(256, 256, kernel_size=(1,7), stride=1, padding=(0,3)), 206 | BasicConv2d(256, 320, kernel_size=(7,1), stride=1, padding=(3,0)), 207 | BasicConv2d(320, 320, kernel_size=3, stride=2) 208 | ) 209 | 210 | self.branch2 = nn.MaxPool2d(3, stride=2) 211 | 212 | def forward(self, x): 213 | x0 = self.branch0(x) 214 | x1 = self.branch1(x) 215 | x2 = self.branch2(x) 216 | out = torch.cat((x0, x1, x2), 1) 217 | return out 218 | 219 | 220 | class Inception_C(nn.Module): 221 | 222 | def __init__(self): 223 | super(Inception_C, self).__init__() 224 | 225 | self.branch0 = BasicConv2d(1536, 256, kernel_size=1, stride=1) 226 | 227 | self.branch1_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1) 228 | self.branch1_1a = BasicConv2d(384, 256, kernel_size=(1,3), stride=1, padding=(0,1)) 229 | self.branch1_1b = BasicConv2d(384, 256, kernel_size=(3,1), stride=1, padding=(1,0)) 230 | 231 | self.branch2_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1) 232 | self.branch2_1 = BasicConv2d(384, 448, kernel_size=(3,1), stride=1, padding=(1,0)) 233 | self.branch2_2 = BasicConv2d(448, 512, kernel_size=(1,3), stride=1, padding=(0,1)) 234 | self.branch2_3a = BasicConv2d(512, 256, kernel_size=(1,3), stride=1, padding=(0,1)) 235 | self.branch2_3b = BasicConv2d(512, 256, kernel_size=(3,1), stride=1, padding=(1,0)) 236 | 237 | self.branch3 = nn.Sequential( 238 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 239 | BasicConv2d(1536, 256, kernel_size=1, stride=1) 240 | ) 241 | 242 | def forward(self, x): 243 | x0 = self.branch0(x) 244 | 245 | x1_0 = self.branch1_0(x) 246 | x1_1a = self.branch1_1a(x1_0) 247 | x1_1b = self.branch1_1b(x1_0) 248 | x1 = torch.cat((x1_1a, x1_1b), 1) 249 | 250 | x2_0 = self.branch2_0(x) 251 | x2_1 = self.branch2_1(x2_0) 252 | x2_2 = self.branch2_2(x2_1) 253 | x2_3a = self.branch2_3a(x2_2) 254 | x2_3b = self.branch2_3b(x2_2) 255 | x2 = torch.cat((x2_3a, x2_3b), 1) 256 | 257 | x3 = self.branch3(x) 258 | 259 | out = torch.cat((x0, x1, x2, x3), 1) 260 | return out 261 | 262 | 263 | class InceptionV4(nn.Module): 264 | 265 | def __init__(self, num_classes=1001): 266 | super(InceptionV4, self).__init__() 267 | # Special attributs 268 | self.input_space = None 269 | self.input_size = (299, 299, 3) 270 | self.mean = None 271 | self.std = None 272 | # Modules 273 | self.features = nn.Sequential( 274 | BasicConv2d(3, 32, kernel_size=3, stride=2), 275 | BasicConv2d(32, 32, kernel_size=3, stride=1), 276 | BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1), 277 | Mixed_3a(), 278 | Mixed_4a(), 279 | Mixed_5a(), 280 | Inception_A(), 281 | Inception_A(), 282 | Inception_A(), 283 | Inception_A(), 284 | Reduction_A(), # Mixed_6a 285 | Inception_B(), 286 | Inception_B(), 287 | Inception_B(), 288 | Inception_B(), 289 | Inception_B(), 290 | Inception_B(), 291 | Inception_B(), 292 | Reduction_B(), # Mixed_7a 293 | Inception_C(), 294 | Inception_C(), 295 | Inception_C() 296 | ) 297 | self.avg_pool = nn.AvgPool2d(8, count_include_pad=False) 298 | self.last_linear = nn.Linear(1536, num_classes) 299 | 300 | def logits(self, features): 301 | x = self.avg_pool(features) 302 | x = x.view(x.size(0), -1) 303 | x = self.last_linear(x) 304 | return x 305 | 306 | def forward(self, input): 307 | x = self.features(input) 308 | x = self.logits(x) 309 | return x 310 | 311 | 312 | def inceptionv4(num_classes=1000, pretrained='imagenet'): 313 | if pretrained: 314 | settings = pretrained_settings['inceptionv4'][pretrained] 315 | assert num_classes == settings['num_classes'], \ 316 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 317 | 318 | # both 'imagenet'&'imagenet+background' are loaded from same parameters 319 | model = InceptionV4(num_classes=1001) 320 | model.load_state_dict(model_zoo.load_url(settings['url'])) 321 | 322 | if pretrained == 'imagenet': 323 | new_last_linear = nn.Linear(1536, 1000) 324 | new_last_linear.weight.data = model.last_linear.weight.data[1:] 325 | new_last_linear.bias.data = model.last_linear.bias.data[1:] 326 | model.last_linear = new_last_linear 327 | 328 | model.input_space = settings['input_space'] 329 | model.input_size = settings['input_size'] 330 | model.input_range = settings['input_range'] 331 | model.mean = settings['mean'] 332 | model.std = settings['std'] 333 | else: 334 | model = InceptionV4(num_classes=num_classes) 335 | return model 336 | 337 | 338 | ''' 339 | TEST 340 | Run this code with: 341 | ``` 342 | cd $HOME/pretrained-models.pytorch 343 | python -m pretrainedmodels.inceptionv4 344 | ``` 345 | ''' 346 | if __name__ == '__main__': 347 | 348 | assert inceptionv4(num_classes=10, pretrained=None) 349 | print('success') 350 | assert inceptionv4(num_classes=1000, pretrained='imagenet') 351 | print('success') 352 | assert inceptionv4(num_classes=1001, pretrained='imagenet+background') 353 | print('success') 354 | 355 | # fail 356 | assert inceptionv4(num_classes=1001, pretrained='imagenet') -------------------------------------------------------------------------------- /phase2/phase2.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import logging 3 | import math 4 | import os 5 | from collections import OrderedDict 6 | import numpy as np 7 | 8 | import torch 9 | from torch import nn, optim 10 | from torch.nn.functional import kl_div, softmax, log_softmax 11 | 12 | from tqdm import tqdm 13 | from theconf import Config as C, ConfigArgumentParser 14 | 15 | from common import get_logger 16 | from data import get_dataloaders 17 | from metrics import accuracy, Accumulator 18 | from networks import get_model, num_class 19 | 20 | from warmup_scheduler import GradualWarmupScheduler 21 | 22 | 23 | logger = get_logger('Unsupervised Data Augmentation') 24 | logger.setLevel(logging.INFO) 25 | 26 | best_valid_top1 = 0 27 | 28 | 29 | def run_epoch(model, loader_s, loader_u, loss_fn, optimizer, desc_default='', epoch=0, writer=None, verbose=1, unsupervised=False, scheduler=None): 30 | #tqdm_disable = bool(os.environ.get('TASK_NAME', '')) 31 | tqdm_disable = C.get()['tqdm_disable'] 32 | if verbose: 33 | loader_s = tqdm(loader_s, disable=tqdm_disable) 34 | loader_s.set_description('[%s %04d/%04d]' % (desc_default, epoch, C.get()['epoch'])) 35 | 36 | iter_u = iter(loader_u) 37 | 38 | metrics = Accumulator() 39 | cnt = 0 40 | total_steps = len(loader_s) 41 | steps = 0 42 | #for data, label, indices in loader_s: 43 | for data, label in loader_s: 44 | steps += 1 45 | ''' 46 | print('labels',label) 47 | np.save('labels', label) 48 | np.save('indices', indices) 49 | print('indices', indices) 50 | raise SystemExit 51 | ''' 52 | if not unsupervised: 53 | data, label = data.cuda(), label.cuda() 54 | preds = model(data) 55 | loss = loss_fn(preds, label) # loss for supervised learning 56 | else: 57 | label = label.cuda() 58 | try: 59 | unlabel1, unlabel2 = next(iter_u) 60 | except StopIteration: 61 | iter_u = iter(loader_u) 62 | unlabel1, unlabel2 = next(iter_u) 63 | data_all = torch.cat([data, unlabel1, unlabel2]).cuda() 64 | #print('DEBUG: data', len(data)) 65 | 66 | preds_all = model(data_all) 67 | preds = preds_all[:len(data)] 68 | 69 | loss = loss_fn(preds, label) # loss for supervised learning 70 | metrics.add_dict({'sup_loss': loss.item() * len(data)}) 71 | 72 | 73 | preds_unsup = preds_all[len(data):] 74 | preds1, preds2 = torch.chunk(preds_unsup, 2) 75 | preds1 = softmax(preds1, dim=1).detach() 76 | preds2 = log_softmax(preds2, dim=1) 77 | assert len(preds1) == len(preds2) == C.get()['batch_unsup'] 78 | 79 | loss_kldiv = kl_div(preds2, preds1, reduction='none') # loss for unsupervised 80 | loss_kldiv = torch.sum(loss_kldiv, dim=1) 81 | assert len(loss_kldiv) == len(unlabel1) 82 | # loss += (epoch / 200. * C.get()['ratio_unsup']) * torch.mean(loss_kldiv) 83 | if C.get()['ratio_mode'] == 'constant': 84 | loss += C.get()['ratio_unsup'] * torch.mean(loss_kldiv) 85 | elif C.get()['ratio_mode'] == 'gradual': 86 | loss += (epoch / float(C.get()['epoch'])) * C.get()['ratio_unsup'] * torch.mean(loss_kldiv) 87 | else: 88 | raise ValueError 89 | 90 | 91 | if optimizer: 92 | loss.backward() 93 | if C.get()['optimizer'].get('clip', 5) > 0: 94 | nn.utils.clip_grad_norm_(model.parameters(), C.get()['optimizer'].get('clip', 5)) 95 | 96 | optimizer.step() 97 | optimizer.zero_grad() 98 | 99 | top1, top5 = accuracy(preds, label, (1, 5)) 100 | 101 | metrics.add_dict({ 102 | 'loss': loss.item() * len(data), 103 | 'top1': top1.item() * len(data), 104 | 'top5': top5.item() * len(data), 105 | }) 106 | cnt += len(data) 107 | if verbose: 108 | postfix = metrics / cnt 109 | if optimizer: 110 | postfix['lr'] = optimizer.param_groups[0]['lr'] 111 | loader_s.set_postfix(postfix) 112 | 113 | if scheduler is not None: 114 | scheduler.step(epoch - 1 + float(steps) / total_steps) 115 | 116 | del preds, loss, top1, top5, data, label 117 | 118 | if tqdm_disable: 119 | logger.info('[%s %03d/%03d] %s', desc_default, epoch, C.get()['epoch'], metrics / cnt) 120 | 121 | metrics /= cnt 122 | if optimizer: 123 | metrics.metrics['lr'] = optimizer.param_groups[0]['lr'] 124 | if verbose: 125 | for key, value in metrics.items(): 126 | writer.add_scalar(key, value, epoch) 127 | return metrics 128 | 129 | 130 | def train_and_eval(tag, dataroot, metric='last', resume=False, save_path=None, only_eval=False, unsupervised=False, devices=None): 131 | max_epoch = C.get()['epoch'] 132 | unsup_idx = C.get()['unsup_idx'] 133 | if os.path.exists(unsup_idx): 134 | unsup_idx = np.load(unsup_idx).tolist() 135 | print('Unsup idx:', len(unsup_idx)) 136 | trainloader, unsuploader, testloader = get_dataloaders(C.get()['dataset'], C.get()['batch'], C.get()['batch_unsup'], 137 | dataroot, with_noise=True, 138 | random_state=C.get()['random_state'], unsup_idx=unsup_idx) 139 | else: 140 | trainloader, unsuploader, testloader = get_dataloaders(C.get()['dataset'], C.get()['batch'], C.get()['batch_unsup'], 141 | dataroot, with_noise=False, 142 | random_state=C.get()['random_state']) 143 | 144 | # create a model & an optimizer 145 | model = get_model(C.get()['model'], num_class(C.get()['dataset']), data_parallel=True, devices=devices) 146 | 147 | criterion = nn.CrossEntropyLoss() 148 | if C.get()['optimizer']['type'] == 'sgd': 149 | optimizer = optim.SGD( 150 | model.parameters(), 151 | lr=C.get()['lr'], 152 | momentum=C.get()['optimizer'].get('momentum', 0.9), 153 | weight_decay=C.get()['optimizer']['decay'], 154 | nesterov=C.get()['optimizer']['nesterov'] 155 | ) 156 | else: 157 | raise ValueError('invalid optimizer type=%s' % C.get()['optimizer']['type']) 158 | 159 | lr_scheduler_type = C.get()['lr_schedule'].get('type', 'cosine') 160 | if lr_scheduler_type == 'cosine': 161 | #t_max = 600 162 | #print('Temp Fix for AnnealingCosine, Tmax=',t_max) 163 | t_max = C.get()['epoch'] 164 | if C.get()['lr_schedule'].get('warmup', None): 165 | t_max -= C.get()['lr_schedule']['warmup']['epoch'] 166 | scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=t_max, eta_min=0.) 167 | else: 168 | raise ValueError('invalid lr_schduler=%s' % lr_scheduler_type) 169 | 170 | if C.get()['lr_schedule'].get('warmup', None): 171 | scheduler = GradualWarmupScheduler( 172 | optimizer, 173 | multiplier=C.get()['lr_schedule']['warmup']['multiplier'], 174 | total_epoch=C.get()['lr_schedule']['warmup']['epoch'], 175 | after_scheduler=scheduler 176 | ) 177 | 178 | if not tag.strip(): 179 | from metrics import SummaryWriterDummy as SummaryWriter 180 | logger.warning('tag not provided, no tensorboard log.') 181 | else: 182 | from tensorboardX import SummaryWriter 183 | writers = [SummaryWriter(logdir='./logs/%s/%s' % (tag, x)) for x in ['train', 'test']] 184 | 185 | result = OrderedDict() 186 | epoch_start = 1 187 | 188 | if (resume or only_eval) and save_path and os.path.exists(save_path): 189 | print('Resuming from last epoch:', save_path) 190 | ckpt = torch.load(save_path) 191 | model.load_state_dict(ckpt['state_dict']) 192 | optimizer.load_state_dict(ckpt['optimizer']) 193 | epoch_start = ckpt['epoch'] 194 | 195 | elif os.path.exists(C.get()['pretrain']): 196 | print('Loading pretrain from:', C.get()['pretrain']) 197 | ckpt = torch.load(C.get()['pretrain']) 198 | try: 199 | model.load_state_dict(ckpt['state_dict']) 200 | except RuntimeError: 201 | new_state_dict = {'module.'+k: v for k, v in ckpt['state_dict'].items()} 202 | model.load_state_dict(new_state_dict) 203 | else: 204 | print('DEBUG: No pretrain available') 205 | 206 | if only_eval: 207 | logger.info('evaluation only+') 208 | model.eval() 209 | rs = dict() 210 | rs['test'] = run_epoch(model, testloader, unsuploader, criterion, None, desc_default='*test', epoch=epoch_start, writer=writers[1]) 211 | for key, setname in itertools.product(['loss', 'top1', 'top5'], ['train', 'test']): 212 | result['%s_%s' % (key, setname)] = rs[setname][key] 213 | result['epoch'] = 0 214 | return result 215 | 216 | # train loop 217 | global best_valid_top1 218 | best_valid_loss = 10e10 219 | for epoch in range(epoch_start, max_epoch + 1): 220 | model.train() 221 | rs = dict() 222 | rs['train'] = run_epoch(model, trainloader, unsuploader, criterion, optimizer, desc_default='train', epoch=epoch, writer=writers[0], verbose=False, unsupervised=unsupervised, scheduler=scheduler) 223 | print('Train At Epoch {}'.format(epoch), rs['train']) 224 | if math.isnan(rs['train']['loss']): 225 | raise Exception('train loss is NaN.') 226 | 227 | model.eval() 228 | if epoch % (10 if 'cifar' in C.get()['dataset'] else 30) == 0 or epoch == max_epoch: 229 | rs['test'] = run_epoch(model, testloader, unsuploader, criterion, None, desc_default='*test', epoch=epoch, writer=writers[1], verbose=False) 230 | print('Test At Epoch {}'.format(epoch), rs['test']) 231 | if best_valid_top1 < rs['test']['top1']: 232 | best_valid_top1 = rs['test']['top1'] 233 | 234 | if metric == 'last' or rs[metric]['loss'] < best_valid_loss: # TODO 235 | if metric != 'last': 236 | best_valid_loss = rs[metric]['loss'] 237 | for key, setname in itertools.product(['loss', 'top1', 'top5'], ['train', 'test']): 238 | result['%s_%s' % (key, setname)] = rs[setname][key] 239 | result['epoch'] = epoch 240 | 241 | writers[1].add_scalar('test_top1/best', rs['test']['top1'], epoch) 242 | 243 | # save checkpoint 244 | if save_path: 245 | logger.info('save model@%d to %s' % (epoch, save_path)) 246 | torch.save({ 247 | 'epoch': epoch, 248 | 'log': { 249 | 'train': rs['train'].get_dict(), 250 | 'test': rs['test'].get_dict(), 251 | }, 252 | 'optimizer': optimizer.state_dict(), 253 | 'state_dict': model.state_dict() 254 | }, save_path) 255 | 256 | del model 257 | 258 | return result 259 | 260 | 261 | if __name__ == '__main__': 262 | parser = ConfigArgumentParser(conflict_handler='resolve') 263 | parser.add_argument('--tag', type=str, default='') 264 | parser.add_argument('--dataroot', type=str, default='../data/', help='torchvision data folder') 265 | parser.add_argument('--save', type=str, default='') 266 | parser.add_argument('--decay', type=float, default=-1) 267 | parser.add_argument('--unsupervised', action='store_true') 268 | parser.add_argument('--only-eval', action='store_true') 269 | parser.add_argument('--gpu', type=int, nargs='+', default=None) 270 | parser.add_argument('--resume', action='store_true') 271 | 272 | args = parser.parse_args() 273 | print('Unsupervised', args.unsupervised) 274 | assert (args.only_eval and not args.save) or not args.only_eval, 'checkpoint path not provided in evaluation mode.' 275 | 276 | if args.decay > 0: 277 | logger.info('decay reset=%.8f' % args.decay) 278 | C.get()['optimizer']['decay'] = args.decay 279 | if args.save: 280 | logger.info('checkpoint will be saved at %s', args.save) 281 | print('ratio_unsup', C.get()['ratio_unsup']) 282 | print('lr', C.get()['lr']) 283 | print('batch ', C.get()['batch'], 'batch_unsup', C.get()['batch_unsup']) 284 | 285 | import time 286 | t = time.time() 287 | result = train_and_eval(args.tag, args.dataroot, resume=args.resume, save_path=args.save, only_eval=args.only_eval, unsupervised=args.unsupervised, devices=args.gpu) 288 | elapsed = time.time() - t 289 | 290 | logger.info('training done.') 291 | logger.info('model: %s' % C.get()['model']) 292 | logger.info('augmentation: %s' % C.get()['aug']) 293 | logger.info(result) 294 | logger.info('elapsed time: %.3f Hours' % (elapsed / 3600.)) 295 | logger.info('top1 error in testset: %.4f' % (1. - result['top1_test'])) 296 | logger.info('best top1 error in testset: %.4f' % (1. - best_valid_top1)) 297 | -------------------------------------------------------------------------------- /phase2/pretrainedmodels/models/inceptionresnetv2.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division, absolute_import 2 | import torch 3 | import torch.nn as nn 4 | import torch.utils.model_zoo as model_zoo 5 | import torch.nn.functional as F 6 | import os 7 | import sys 8 | 9 | __all__ = ['InceptionResNetV2', 'inceptionresnetv2'] 10 | 11 | pretrained_settings = { 12 | 'inceptionresnetv2': { 13 | 'imagenet': { 14 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionresnetv2-520b38e4.pth', 15 | 'input_space': 'RGB', 16 | 'input_size': [3, 299, 299], 17 | 'input_range': [0, 1], 18 | 'mean': [0.5, 0.5, 0.5], 19 | 'std': [0.5, 0.5, 0.5], 20 | 'num_classes': 1000 21 | }, 22 | 'imagenet+background': { 23 | 'url': 'http://data.lip6.fr/cadene/pretrainedmodels/inceptionresnetv2-520b38e4.pth', 24 | 'input_space': 'RGB', 25 | 'input_size': [3, 299, 299], 26 | 'input_range': [0, 1], 27 | 'mean': [0.5, 0.5, 0.5], 28 | 'std': [0.5, 0.5, 0.5], 29 | 'num_classes': 1001 30 | } 31 | } 32 | } 33 | 34 | 35 | class BasicConv2d(nn.Module): 36 | 37 | def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0): 38 | super(BasicConv2d, self).__init__() 39 | self.conv = nn.Conv2d(in_planes, out_planes, 40 | kernel_size=kernel_size, stride=stride, 41 | padding=padding, bias=False) # verify bias false 42 | self.bn = nn.BatchNorm2d(out_planes, 43 | eps=0.001, # value found in tensorflow 44 | momentum=0.1, # default pytorch value 45 | affine=True) 46 | self.relu = nn.ReLU(inplace=False) 47 | 48 | def forward(self, x): 49 | x = self.conv(x) 50 | x = self.bn(x) 51 | x = self.relu(x) 52 | return x 53 | 54 | 55 | class Mixed_5b(nn.Module): 56 | 57 | def __init__(self): 58 | super(Mixed_5b, self).__init__() 59 | 60 | self.branch0 = BasicConv2d(192, 96, kernel_size=1, stride=1) 61 | 62 | self.branch1 = nn.Sequential( 63 | BasicConv2d(192, 48, kernel_size=1, stride=1), 64 | BasicConv2d(48, 64, kernel_size=5, stride=1, padding=2) 65 | ) 66 | 67 | self.branch2 = nn.Sequential( 68 | BasicConv2d(192, 64, kernel_size=1, stride=1), 69 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1), 70 | BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1) 71 | ) 72 | 73 | self.branch3 = nn.Sequential( 74 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 75 | BasicConv2d(192, 64, kernel_size=1, stride=1) 76 | ) 77 | 78 | def forward(self, x): 79 | x0 = self.branch0(x) 80 | x1 = self.branch1(x) 81 | x2 = self.branch2(x) 82 | x3 = self.branch3(x) 83 | out = torch.cat((x0, x1, x2, x3), 1) 84 | return out 85 | 86 | 87 | class Block35(nn.Module): 88 | 89 | def __init__(self, scale=1.0): 90 | super(Block35, self).__init__() 91 | 92 | self.scale = scale 93 | 94 | self.branch0 = BasicConv2d(320, 32, kernel_size=1, stride=1) 95 | 96 | self.branch1 = nn.Sequential( 97 | BasicConv2d(320, 32, kernel_size=1, stride=1), 98 | BasicConv2d(32, 32, kernel_size=3, stride=1, padding=1) 99 | ) 100 | 101 | self.branch2 = nn.Sequential( 102 | BasicConv2d(320, 32, kernel_size=1, stride=1), 103 | BasicConv2d(32, 48, kernel_size=3, stride=1, padding=1), 104 | BasicConv2d(48, 64, kernel_size=3, stride=1, padding=1) 105 | ) 106 | 107 | self.conv2d = nn.Conv2d(128, 320, kernel_size=1, stride=1) 108 | self.relu = nn.ReLU(inplace=False) 109 | 110 | def forward(self, x): 111 | x0 = self.branch0(x) 112 | x1 = self.branch1(x) 113 | x2 = self.branch2(x) 114 | out = torch.cat((x0, x1, x2), 1) 115 | out = self.conv2d(out) 116 | out = out * self.scale + x 117 | out = self.relu(out) 118 | return out 119 | 120 | 121 | class Mixed_6a(nn.Module): 122 | 123 | def __init__(self): 124 | super(Mixed_6a, self).__init__() 125 | 126 | self.branch0 = BasicConv2d(320, 384, kernel_size=3, stride=2) 127 | 128 | self.branch1 = nn.Sequential( 129 | BasicConv2d(320, 256, kernel_size=1, stride=1), 130 | BasicConv2d(256, 256, kernel_size=3, stride=1, padding=1), 131 | BasicConv2d(256, 384, kernel_size=3, stride=2) 132 | ) 133 | 134 | self.branch2 = nn.MaxPool2d(3, stride=2) 135 | 136 | def forward(self, x): 137 | x0 = self.branch0(x) 138 | x1 = self.branch1(x) 139 | x2 = self.branch2(x) 140 | out = torch.cat((x0, x1, x2), 1) 141 | return out 142 | 143 | 144 | class Block17(nn.Module): 145 | 146 | def __init__(self, scale=1.0): 147 | super(Block17, self).__init__() 148 | 149 | self.scale = scale 150 | 151 | self.branch0 = BasicConv2d(1088, 192, kernel_size=1, stride=1) 152 | 153 | self.branch1 = nn.Sequential( 154 | BasicConv2d(1088, 128, kernel_size=1, stride=1), 155 | BasicConv2d(128, 160, kernel_size=(1,7), stride=1, padding=(0,3)), 156 | BasicConv2d(160, 192, kernel_size=(7,1), stride=1, padding=(3,0)) 157 | ) 158 | 159 | self.conv2d = nn.Conv2d(384, 1088, kernel_size=1, stride=1) 160 | self.relu = nn.ReLU(inplace=False) 161 | 162 | def forward(self, x): 163 | x0 = self.branch0(x) 164 | x1 = self.branch1(x) 165 | out = torch.cat((x0, x1), 1) 166 | out = self.conv2d(out) 167 | out = out * self.scale + x 168 | out = self.relu(out) 169 | return out 170 | 171 | 172 | class Mixed_7a(nn.Module): 173 | 174 | def __init__(self): 175 | super(Mixed_7a, self).__init__() 176 | 177 | self.branch0 = nn.Sequential( 178 | BasicConv2d(1088, 256, kernel_size=1, stride=1), 179 | BasicConv2d(256, 384, kernel_size=3, stride=2) 180 | ) 181 | 182 | self.branch1 = nn.Sequential( 183 | BasicConv2d(1088, 256, kernel_size=1, stride=1), 184 | BasicConv2d(256, 288, kernel_size=3, stride=2) 185 | ) 186 | 187 | self.branch2 = nn.Sequential( 188 | BasicConv2d(1088, 256, kernel_size=1, stride=1), 189 | BasicConv2d(256, 288, kernel_size=3, stride=1, padding=1), 190 | BasicConv2d(288, 320, kernel_size=3, stride=2) 191 | ) 192 | 193 | self.branch3 = nn.MaxPool2d(3, stride=2) 194 | 195 | def forward(self, x): 196 | x0 = self.branch0(x) 197 | x1 = self.branch1(x) 198 | x2 = self.branch2(x) 199 | x3 = self.branch3(x) 200 | out = torch.cat((x0, x1, x2, x3), 1) 201 | return out 202 | 203 | 204 | class Block8(nn.Module): 205 | 206 | def __init__(self, scale=1.0, noReLU=False): 207 | super(Block8, self).__init__() 208 | 209 | self.scale = scale 210 | self.noReLU = noReLU 211 | 212 | self.branch0 = BasicConv2d(2080, 192, kernel_size=1, stride=1) 213 | 214 | self.branch1 = nn.Sequential( 215 | BasicConv2d(2080, 192, kernel_size=1, stride=1), 216 | BasicConv2d(192, 224, kernel_size=(1,3), stride=1, padding=(0,1)), 217 | BasicConv2d(224, 256, kernel_size=(3,1), stride=1, padding=(1,0)) 218 | ) 219 | 220 | self.conv2d = nn.Conv2d(448, 2080, kernel_size=1, stride=1) 221 | if not self.noReLU: 222 | self.relu = nn.ReLU(inplace=False) 223 | 224 | def forward(self, x): 225 | x0 = self.branch0(x) 226 | x1 = self.branch1(x) 227 | out = torch.cat((x0, x1), 1) 228 | out = self.conv2d(out) 229 | out = out * self.scale + x 230 | if not self.noReLU: 231 | out = self.relu(out) 232 | return out 233 | 234 | 235 | class InceptionResNetV2(nn.Module): 236 | 237 | def __init__(self, num_classes=1001): 238 | super(InceptionResNetV2, self).__init__() 239 | # Special attributs 240 | self.input_space = None 241 | self.input_size = (299, 299, 3) 242 | self.mean = None 243 | self.std = None 244 | # Modules 245 | self.conv2d_1a = BasicConv2d(3, 32, kernel_size=3, stride=2) 246 | self.conv2d_2a = BasicConv2d(32, 32, kernel_size=3, stride=1) 247 | self.conv2d_2b = BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1) 248 | self.maxpool_3a = nn.MaxPool2d(3, stride=2) 249 | self.conv2d_3b = BasicConv2d(64, 80, kernel_size=1, stride=1) 250 | self.conv2d_4a = BasicConv2d(80, 192, kernel_size=3, stride=1) 251 | self.maxpool_5a = nn.MaxPool2d(3, stride=2) 252 | self.mixed_5b = Mixed_5b() 253 | self.repeat = nn.Sequential( 254 | Block35(scale=0.17), 255 | Block35(scale=0.17), 256 | Block35(scale=0.17), 257 | Block35(scale=0.17), 258 | Block35(scale=0.17), 259 | Block35(scale=0.17), 260 | Block35(scale=0.17), 261 | Block35(scale=0.17), 262 | Block35(scale=0.17), 263 | Block35(scale=0.17) 264 | ) 265 | self.mixed_6a = Mixed_6a() 266 | self.repeat_1 = nn.Sequential( 267 | Block17(scale=0.10), 268 | Block17(scale=0.10), 269 | Block17(scale=0.10), 270 | Block17(scale=0.10), 271 | Block17(scale=0.10), 272 | Block17(scale=0.10), 273 | Block17(scale=0.10), 274 | Block17(scale=0.10), 275 | Block17(scale=0.10), 276 | Block17(scale=0.10), 277 | Block17(scale=0.10), 278 | Block17(scale=0.10), 279 | Block17(scale=0.10), 280 | Block17(scale=0.10), 281 | Block17(scale=0.10), 282 | Block17(scale=0.10), 283 | Block17(scale=0.10), 284 | Block17(scale=0.10), 285 | Block17(scale=0.10), 286 | Block17(scale=0.10) 287 | ) 288 | self.mixed_7a = Mixed_7a() 289 | self.repeat_2 = nn.Sequential( 290 | Block8(scale=0.20), 291 | Block8(scale=0.20), 292 | Block8(scale=0.20), 293 | Block8(scale=0.20), 294 | Block8(scale=0.20), 295 | Block8(scale=0.20), 296 | Block8(scale=0.20), 297 | Block8(scale=0.20), 298 | Block8(scale=0.20) 299 | ) 300 | self.block8 = Block8(noReLU=True) 301 | self.conv2d_7b = BasicConv2d(2080, 1536, kernel_size=1, stride=1) 302 | self.avgpool_1a = nn.AvgPool2d(8, count_include_pad=False) 303 | self.last_linear = nn.Linear(1536, num_classes) 304 | 305 | def features(self, input): 306 | x = self.conv2d_1a(input) 307 | x = self.conv2d_2a(x) 308 | x = self.conv2d_2b(x) 309 | x = self.maxpool_3a(x) 310 | x = self.conv2d_3b(x) 311 | x = self.conv2d_4a(x) 312 | x = self.maxpool_5a(x) 313 | x = self.mixed_5b(x) 314 | x = self.repeat(x) 315 | x = self.mixed_6a(x) 316 | x = self.repeat_1(x) 317 | x = self.mixed_7a(x) 318 | x = self.repeat_2(x) 319 | x = self.block8(x) 320 | x = self.conv2d_7b(x) 321 | return x 322 | 323 | def logits(self, features): 324 | x = self.avgpool_1a(features) 325 | x = x.view(x.size(0), -1) 326 | x = F.dropout(x, training=self.training) 327 | x = self.last_linear(x) 328 | return x 329 | 330 | def forward(self, input): 331 | x = self.features(input) 332 | x = self.logits(x) 333 | return x 334 | 335 | def inceptionresnetv2(num_classes=1000, pretrained='imagenet'): 336 | r"""InceptionResNetV2 model architecture from the 337 | `"InceptionV4, Inception-ResNet..." `_ paper. 338 | """ 339 | if pretrained: 340 | settings = pretrained_settings['inceptionresnetv2'][pretrained] 341 | assert num_classes == settings['num_classes'], \ 342 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes) 343 | 344 | # both 'imagenet'&'imagenet+background' are loaded from same parameters 345 | model = InceptionResNetV2(num_classes=1001) 346 | model.load_state_dict(model_zoo.load_url(settings['url'])) 347 | 348 | if pretrained == 'imagenet': 349 | new_last_linear = nn.Linear(1536, 1000) 350 | new_last_linear.weight.data = model.last_linear.weight.data[1:] 351 | new_last_linear.bias.data = model.last_linear.bias.data[1:] 352 | model.last_linear = new_last_linear 353 | 354 | model.input_space = settings['input_space'] 355 | model.input_size = settings['input_size'] 356 | model.input_range = settings['input_range'] 357 | 358 | model.mean = settings['mean'] 359 | model.std = settings['std'] 360 | else: 361 | model = InceptionResNetV2(num_classes=num_classes) 362 | return model 363 | 364 | ''' 365 | TEST 366 | Run this code with: 367 | ``` 368 | cd $HOME/pretrained-models.pytorch 369 | python -m pretrainedmodels.inceptionresnetv2 370 | ``` 371 | ''' 372 | if __name__ == '__main__': 373 | 374 | assert inceptionresnetv2(num_classes=10, pretrained=None) 375 | print('success') 376 | assert inceptionresnetv2(num_classes=1000, pretrained='imagenet') 377 | print('success') 378 | assert inceptionresnetv2(num_classes=1001, pretrained='imagenet+background') 379 | print('success') 380 | 381 | # fail 382 | assert inceptionresnetv2(num_classes=1001, pretrained='imagenet') -------------------------------------------------------------------------------- /phase2/noisy_cifar.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from PIL import Image 3 | import os 4 | import os.path 5 | import numpy as np 6 | import sys 7 | if sys.version_info[0] == 2: 8 | import cPickle as pickle 9 | else: 10 | import pickle 11 | 12 | import torch.utils.data as data 13 | from .utils import download_url, check_integrity, noisify 14 | 15 | class Noisy_CIFAR10(data.Dataset): 16 | """`CIFAR10 `_ Dataset. 17 | 18 | Args: 19 | root (string): Root directory of dataset where directory 20 | ``cifar-10-batches-py`` exists or will be saved to if download is set to True. 21 | train (bool, optional): If True, creates dataset from training set, otherwise 22 | creates from test set. 23 | transform (callable, optional): A function/transform that takes in an PIL image 24 | and returns a transformed version. E.g, ``transforms.RandomCrop`` 25 | target_transform (callable, optional): A function/transform that takes in the 26 | target and transforms it. 27 | download (bool, optional): If true, downloads the dataset from the internet and 28 | puts it in root directory. If dataset is already downloaded, it is not 29 | downloaded again. 30 | 31 | """ 32 | base_folder = 'cifar-10-batches-py' 33 | url = "https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz" 34 | filename = "cifar-10-python.tar.gz" 35 | tgz_md5 = 'c58f30108f718f92721af3b95e74349a' 36 | train_list = [ 37 | ['data_batch_1', 'c99cafc152244af753f735de768cd75f'], 38 | ['data_batch_2', 'd4bba439e000b95fd0a9bffe97cbabec'], 39 | ['data_batch_3', '54ebc095f3ab1f0389bbae665268c751'], 40 | ['data_batch_4', '634d18415352ddfa80567beed471001a'], 41 | ['data_batch_5', '482c414d41f54cd18b22e5b47cb7c3cb'], 42 | ] 43 | 44 | test_list = [ 45 | ['test_batch', '40351d587109b95175f43aff81a1287e'], 46 | ] 47 | 48 | def __init__(self, root, train=True, 49 | transform=None, target_transform=None, 50 | download=False, 51 | noise_type=None, noise_rate=0.2, random_state=0): 52 | self.root = os.path.expanduser(root) 53 | self.transform = transform 54 | self.target_transform = target_transform 55 | self.train = train # training set or test set 56 | self.dataset='cifar10' 57 | self.noise_type=noise_type 58 | self.nb_classes=10 59 | 60 | #if download: 61 | # self.download() 62 | 63 | #if not self._check_integrity(): 64 | # raise RuntimeError('Dataset not found or corrupted.' + 65 | # ' You can use download=True to download it') 66 | 67 | # now load the picked numpy arrays 68 | if self.train: 69 | self.train_data = [] 70 | self.train_labels = [] 71 | for fentry in self.train_list: 72 | f = fentry[0] 73 | file = os.path.join(self.root, self.base_folder, f) 74 | fo = open(file, 'rb') 75 | if sys.version_info[0] == 2: 76 | entry = pickle.load(fo) 77 | else: 78 | entry = pickle.load(fo, encoding='latin1') 79 | self.train_data.append(entry['data']) 80 | if 'labels' in entry: 81 | self.train_labels += entry['labels'] 82 | else: 83 | self.train_labels += entry['fine_labels'] 84 | fo.close() 85 | 86 | self.train_data = np.concatenate(self.train_data) 87 | self.train_data = self.train_data.reshape((50000, 3, 32, 32)) 88 | self.train_data = self.train_data.transpose((0, 2, 3, 1)) # convert to HWC 89 | #if noise_type is not None: 90 | if noise_type !='clean': 91 | # noisify train data 92 | self.train_labels=np.asarray([[self.train_labels[i]] for i in range(len(self.train_labels))]) 93 | self.train_noisy_labels, self.actual_noise_rate = noisify(dataset=self.dataset, train_labels=self.train_labels, noise_type=noise_type, noise_rate=noise_rate, random_state=random_state, nb_classes=self.nb_classes) 94 | self.train_noisy_labels=[i[0] for i in self.train_noisy_labels] 95 | _train_labels=[i[0] for i in self.train_labels] 96 | self.noise_or_not = np.transpose(self.train_noisy_labels)!=np.transpose(_train_labels) 97 | else: 98 | f = self.test_list[0][0] 99 | file = os.path.join(self.root, self.base_folder, f) 100 | fo = open(file, 'rb') 101 | if sys.version_info[0] == 2: 102 | entry = pickle.load(fo) 103 | else: 104 | entry = pickle.load(fo, encoding='latin1') 105 | self.test_data = entry['data'] 106 | if 'labels' in entry: 107 | self.test_labels = entry['labels'] 108 | else: 109 | self.test_labels = entry['fine_labels'] 110 | fo.close() 111 | self.test_data = self.test_data.reshape((10000, 3, 32, 32)) 112 | self.test_data = self.test_data.transpose((0, 2, 3, 1)) # convert to HWC 113 | 114 | def __getitem__(self, index): 115 | """ 116 | Args: 117 | index (int): Index 118 | 119 | Returns: 120 | tuple: (image, target) where target is index of the target class. 121 | """ 122 | if self.train: 123 | if self.noise_type !='clean': 124 | img, target = self.train_data[index], self.train_noisy_labels[index] 125 | else: 126 | img, target = self.train_data[index], self.train_labels[index] 127 | else: 128 | img, target = self.test_data[index], self.test_labels[index] 129 | 130 | # doing this so that it is consistent with all other datasets 131 | # to return a PIL Image 132 | img = Image.fromarray(img) 133 | 134 | if self.transform is not None: 135 | img = self.transform(img) 136 | 137 | if self.target_transform is not None: 138 | target = self.target_transform(target) 139 | 140 | return img, target, index 141 | 142 | def __len__(self): 143 | if self.train: 144 | return len(self.train_data) 145 | else: 146 | return len(self.test_data) 147 | 148 | def _check_integrity(self): 149 | root = self.root 150 | for fentry in (self.train_list + self.test_list): 151 | filename, md5 = fentry[0], fentry[1] 152 | fpath = os.path.join(root, self.base_folder, filename) 153 | if not check_integrity(fpath, md5): 154 | return False 155 | return True 156 | 157 | def download(self): 158 | import tarfile 159 | 160 | if self._check_integrity(): 161 | print('Files already downloaded and verified') 162 | return 163 | 164 | root = self.root 165 | download_url(self.url, root, self.filename, self.tgz_md5) 166 | 167 | # extract file 168 | cwd = os.getcwd() 169 | tar = tarfile.open(os.path.join(root, self.filename), "r:gz") 170 | os.chdir(root) 171 | tar.extractall() 172 | tar.close() 173 | os.chdir(cwd) 174 | 175 | def __repr__(self): 176 | fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' 177 | fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) 178 | tmp = 'train' if self.train is True else 'test' 179 | fmt_str += ' Split: {}\n'.format(tmp) 180 | fmt_str += ' Root Location: {}\n'.format(self.root) 181 | tmp = ' Transforms (if any): ' 182 | fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 183 | tmp = ' Target Transforms (if any): ' 184 | fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 185 | return fmt_str 186 | 187 | class CIFAR100(data.Dataset): 188 | """`CIFAR100 `_ Dataset. 189 | 190 | Args: 191 | root (string): Root directory of dataset where directory 192 | ``cifar-10-batches-py`` exists or will be saved to if download is set to True. 193 | train (bool, optional): If True, creates dataset from training set, otherwise 194 | creates from test set. 195 | transform (callable, optional): A function/transform that takes in an PIL image 196 | and returns a transformed version. E.g, ``transforms.RandomCrop`` 197 | target_transform (callable, optional): A function/transform that takes in the 198 | target and transforms it. 199 | download (bool, optional): If true, downloads the dataset from the internet and 200 | puts it in root directory. If dataset is already downloaded, it is not 201 | downloaded again. 202 | 203 | """ 204 | base_folder = 'cifar-100-python' 205 | url = "https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz" 206 | filename = "cifar-100-python.tar.gz" 207 | tgz_md5 = 'eb9058c3a382ffc7106e4002c42a8d85' 208 | train_list = [ 209 | ['train', '16019d7e3df5f24257cddd939b257f8d'], 210 | ] 211 | 212 | test_list = [ 213 | ['test', 'f0ef6b0ae62326f3e7ffdfab6717acfc'], 214 | ] 215 | 216 | 217 | def __init__(self, root, train=True, 218 | transform=None, target_transform=None, 219 | download=False, 220 | noise_type=None, noise_rate=0.2, random_state=0): 221 | self.root = os.path.expanduser(root) 222 | self.transform = transform 223 | self.target_transform = target_transform 224 | self.train = train # training set or test set 225 | self.dataset='cifar100' 226 | self.noise_type=noise_type 227 | self.nb_classes=100 228 | 229 | if download: 230 | self.download() 231 | 232 | if not self._check_integrity(): 233 | raise RuntimeError('Dataset not found or corrupted.' + 234 | ' You can use download=True to download it') 235 | 236 | # now load the picked numpy arrays 237 | if self.train: 238 | self.train_data = [] 239 | self.train_labels = [] 240 | for fentry in self.train_list: 241 | f = fentry[0] 242 | file = os.path.join(self.root, self.base_folder, f) 243 | fo = open(file, 'rb') 244 | if sys.version_info[0] == 2: 245 | entry = pickle.load(fo) 246 | else: 247 | entry = pickle.load(fo, encoding='latin1') 248 | self.train_data.append(entry['data']) 249 | if 'labels' in entry: 250 | self.train_labels += entry['labels'] 251 | else: 252 | self.train_labels += entry['fine_labels'] 253 | fo.close() 254 | 255 | self.train_data = np.concatenate(self.train_data) 256 | self.train_data = self.train_data.reshape((50000, 3, 32, 32)) 257 | self.train_data = self.train_data.transpose((0, 2, 3, 1)) # convert to HWC 258 | if noise_type is not None: 259 | # noisify train data 260 | self.train_labels=np.asarray([[self.train_labels[i]] for i in range(len(self.train_labels))]) 261 | self.train_noisy_labels, self.actual_noise_rate = noisify(dataset=self.dataset, train_labels=self.train_labels, noise_type=noise_type, noise_rate=noise_rate, random_state=random_state, nb_classes=self.nb_classes) 262 | self.train_noisy_labels=[i[0] for i in self.train_noisy_labels] 263 | _train_labels=[i[0] for i in self.train_labels] 264 | self.noise_or_not = np.transpose(self.train_noisy_labels)!=np.transpose(_train_labels) 265 | else: 266 | f = self.test_list[0][0] 267 | file = os.path.join(self.root, self.base_folder, f) 268 | fo = open(file, 'rb') 269 | if sys.version_info[0] == 2: 270 | entry = pickle.load(fo) 271 | else: 272 | entry = pickle.load(fo, encoding='latin1') 273 | self.test_data = entry['data'] 274 | if 'labels' in entry: 275 | self.test_labels = entry['labels'] 276 | else: 277 | self.test_labels = entry['fine_labels'] 278 | fo.close() 279 | self.test_data = self.test_data.reshape((10000, 3, 32, 32)) 280 | self.test_data = self.test_data.transpose((0, 2, 3, 1)) # convert to HWC 281 | 282 | def __getitem__(self, index): 283 | """ 284 | Args: 285 | index (int): Index 286 | 287 | Returns: 288 | tuple: (image, target) where target is index of the target class. 289 | """ 290 | if self.train: 291 | if self.noise_type is not None: 292 | img, target = self.train_data[index], self.train_noisy_labels[index] 293 | else: 294 | img, target = self.train_data[index], self.train_labels[index] 295 | else: 296 | img, target = self.test_data[index], self.test_labels[index] 297 | 298 | # doing this so that it is consistent with all other datasets 299 | # to return a PIL Image 300 | img = Image.fromarray(img) 301 | 302 | if self.transform is not None: 303 | img = self.transform(img) 304 | 305 | if self.target_transform is not None: 306 | target = self.target_transform(target) 307 | 308 | return img, target, index 309 | 310 | def __len__(self): 311 | if self.train: 312 | return len(self.train_data) 313 | else: 314 | return len(self.test_data) 315 | 316 | def _check_integrity(self): 317 | root = self.root 318 | for fentry in (self.train_list + self.test_list): 319 | filename, md5 = fentry[0], fentry[1] 320 | fpath = os.path.join(root, self.base_folder, filename) 321 | if not check_integrity(fpath, md5): 322 | return False 323 | return True 324 | 325 | def download(self): 326 | import tarfile 327 | 328 | if self._check_integrity(): 329 | print('Files already downloaded and verified') 330 | return 331 | 332 | root = self.root 333 | download_url(self.url, root, self.filename, self.tgz_md5) 334 | 335 | # extract file 336 | cwd = os.getcwd() 337 | tar = tarfile.open(os.path.join(root, self.filename), "r:gz") 338 | os.chdir(root) 339 | tar.extractall() 340 | tar.close() 341 | os.chdir(cwd) 342 | 343 | def __repr__(self): 344 | fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' 345 | fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) 346 | tmp = 'train' if self.train is True else 'test' 347 | fmt_str += ' Split: {}\n'.format(tmp) 348 | fmt_str += ' Root Location: {}\n'.format(self.root) 349 | tmp = ' Transforms (if any): ' 350 | fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 351 | tmp = ' Target Transforms (if any): ' 352 | fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 353 | return fmt_str 354 | 355 | 356 | --------------------------------------------------------------------------------