├── ImageNet ├── algorithms │ ├── Algorithm.py │ ├── FeatureClassificationModel.py │ ├── UnsupervisedModel.py │ └── __init__.py ├── architectures │ ├── AlexNet.py │ ├── LinearClassifier.py │ ├── MultipleLinearClassifiers.py │ ├── MultipleNonLinearClassifiers.py │ └── NonLinearClassifier.py ├── config │ ├── ImageNet_LinearClassifiers_Avgpooling.py │ ├── ImageNet_LinearClassifiers_Maxpooling.py │ ├── ImageNet_NonLinearClassifiers.py │ ├── ImageNet_Unsupervised.py │ ├── Places205_LinearClassifiers_Avgpooling.py │ └── Places205_LinearClassifiers_Maxpooling.py ├── dataloader.py ├── main.py ├── save_homography.py └── utils.py ├── README.md ├── cifar ├── NetworkInNetwork.py ├── NonLinearClassifier.py ├── classification.py ├── dataset.py ├── get_mean_std.py ├── main.py └── utils │ ├── __init__.py │ ├── __init__.pyc │ ├── eval.py │ ├── eval.pyc │ ├── logger.py │ ├── logger.pyc │ ├── misc.py │ ├── misc.pyc │ ├── progress │ ├── LICENSE │ ├── MANIFEST.in │ ├── README.rst │ ├── progress │ │ ├── __init__.py │ │ ├── __init__.pyc │ │ ├── bar.py │ │ ├── bar.pyc │ │ ├── counter.py │ │ ├── helpers.py │ │ ├── helpers.pyc │ │ └── spinner.py │ ├── setup.py │ └── test_progress.py │ ├── visualize.py │ └── visualize.pyc └── resources └── AVT.PNG /ImageNet/algorithms/Algorithm.py: -------------------------------------------------------------------------------- 1 | """Define a generic class for training and testing learning algorithms.""" 2 | from __future__ import print_function 3 | import os 4 | import os.path 5 | import imp 6 | from tqdm import tqdm 7 | 8 | import torch 9 | import torch.nn as nn 10 | import torch.optim 11 | 12 | import utils 13 | import datetime 14 | import logging 15 | 16 | from pdb import set_trace as breakpoint 17 | 18 | class Algorithm(): 19 | def __init__(self, opt): 20 | self.set_experiment_dir(opt['exp_dir']) 21 | self.set_log_file_handler() 22 | 23 | self.logger.info('Algorithm options %s' % opt) 24 | self.opt = opt 25 | self.init_all_networks() 26 | self.init_all_criterions() 27 | self.allocate_tensors() 28 | self.curr_epoch = 0 29 | self.optimizers = {} 30 | 31 | self.keep_best_model_metric_name = opt['best_metric'] if ('best_metric' in opt) else None 32 | 33 | def set_experiment_dir(self,directory_path): 34 | self.exp_dir = directory_path 35 | if (not os.path.isdir(self.exp_dir)): 36 | os.makedirs(self.exp_dir) 37 | 38 | self.vis_dir = os.path.join(directory_path,'visuals') 39 | if (not os.path.isdir(self.vis_dir)): 40 | os.makedirs(self.vis_dir) 41 | 42 | self.preds_dir = os.path.join(directory_path,'preds') 43 | if (not os.path.isdir(self.preds_dir)): 44 | os.makedirs(self.preds_dir) 45 | 46 | def set_log_file_handler(self): 47 | self.logger = logging.getLogger(__name__) 48 | 49 | strHandler = logging.StreamHandler() 50 | formatter = logging.Formatter( 51 | '%(asctime)s - %(name)-8s - %(levelname)-6s - %(message)s') 52 | strHandler.setFormatter(formatter) 53 | self.logger.addHandler(strHandler) 54 | self.logger.setLevel(logging.INFO) 55 | 56 | log_dir = os.path.join(self.exp_dir, 'logs') 57 | if (not os.path.isdir(log_dir)): 58 | os.makedirs(log_dir) 59 | 60 | now_str = datetime.datetime.now().__str__().replace(' ','_') 61 | 62 | self.log_file = os.path.join(log_dir, 'LOG_INFO_'+now_str+'.txt') 63 | self.log_fileHandler = logging.FileHandler(self.log_file) 64 | self.log_fileHandler.setFormatter(formatter) 65 | self.logger.addHandler(self.log_fileHandler) 66 | 67 | def init_all_networks(self): 68 | networks_defs = self.opt['networks'] 69 | self.networks = {} 70 | self.optim_params = {} 71 | 72 | for key, val in networks_defs.items(): 73 | self.logger.info('Set network %s' % key) 74 | def_file = val['def_file'] 75 | net_opt = val['opt'] 76 | self.optim_params[key] = val['optim_params'] if ('optim_params' in val) else None 77 | pretrained_path = val['pretrained'] if ('pretrained' in val) else None 78 | self.networks[key] = self.init_network(def_file, net_opt, pretrained_path, key) 79 | 80 | def init_network(self, net_def_file, net_opt, pretrained_path, key): 81 | self.logger.info('==> Initiliaze network %s from file %s with opts: %s' % (key, net_def_file, net_opt)) 82 | if (not os.path.isfile(net_def_file)): 83 | raise ValueError('Non existing file: {0}'.format(net_def_file)) 84 | 85 | network = imp.load_source("",net_def_file).create_model(net_opt) 86 | if pretrained_path != None: 87 | self.load_pretrained(network, pretrained_path) 88 | 89 | return network 90 | 91 | def load_pretrained(self, network, pretrained_path): 92 | self.logger.info('==> Load pretrained parameters from file %s:' % (pretrained_path)) 93 | 94 | assert(os.path.isfile(pretrained_path)) 95 | pretrained_model = torch.load(pretrained_path) 96 | if pretrained_model['network'].keys() == network.state_dict().keys(): 97 | network.load_state_dict(pretrained_model['network']) 98 | else: 99 | self.logger.info('==> WARNING: network parameters in pre-trained file %s do not strictly match' % (pretrained_path)) 100 | for pname, param in network.named_parameters(): 101 | if pname in pretrained_model['network']: 102 | self.logger.info('==> Copying parameter %s from file %s' % (pname, pretrained_path)) 103 | param.data.copy_(pretrained_model['network'][pname]) 104 | 105 | def init_all_optimizers(self): 106 | self.optimizers = {} 107 | 108 | for key, oparams in self.optim_params.items(): 109 | self.optimizers[key] = None 110 | if oparams != None: 111 | self.optimizers[key] = self.init_optimizer( 112 | self.networks[key], oparams, key) 113 | 114 | def init_optimizer(self, net, optim_opts, key): 115 | optim_type = optim_opts['optim_type'] 116 | learning_rate = optim_opts['lr'] 117 | optimizer = None 118 | parameters = filter(lambda p: p.requires_grad, net.parameters()) 119 | self.logger.info('Initialize optimizer: %s with params: %s for netwotk: %s' 120 | % (optim_type, optim_opts, key)) 121 | if optim_type == 'adam': 122 | optimizer = torch.optim.Adam(parameters, lr=learning_rate, 123 | betas=optim_opts['beta']) 124 | elif optim_type == 'sgd': 125 | optimizer = torch.optim.SGD(parameters, lr=learning_rate, 126 | momentum=optim_opts['momentum'], 127 | nesterov=optim_opts['nesterov'] if ('nesterov' in optim_opts) else False, 128 | weight_decay=optim_opts['weight_decay']) 129 | else: 130 | raise ValueError('Not supported or recognized optim_type', optim_type) 131 | 132 | return optimizer 133 | 134 | def init_all_criterions(self): 135 | criterions_defs = self.opt['criterions'] 136 | self.criterions = {} 137 | for key, val in criterions_defs.items(): 138 | crit_type = val['ctype'] 139 | crit_opt = val['opt'] if ('opt' in val) else None 140 | self.logger.info('Initialize criterion[%s]: %s with options: %s' % (key, crit_type, crit_opt)) 141 | self.criterions[key] = self.init_criterion(crit_type, crit_opt) 142 | 143 | def init_criterion(self, ctype, copt): 144 | return getattr(nn, ctype)(copt) 145 | 146 | def load_to_gpu(self): 147 | for key, net in self.networks.items(): 148 | # net = torch.nn.DataParallel(net, device_ids = range(1)) 149 | self.networks[key] = net.cuda() 150 | 151 | for key, criterion in self.criterions.items(): 152 | self.criterions[key] = criterion.cuda() 153 | 154 | for key, tensor in self.tensors.items(): 155 | self.tensors[key] = tensor.cuda() 156 | 157 | def save_checkpoint(self, epoch, suffix=''): 158 | for key, net in self.networks.items(): 159 | if self.optimizers[key] == None: continue 160 | self.save_network(key, epoch, suffix=suffix) 161 | self.save_optimizer(key, epoch, suffix=suffix) 162 | 163 | def load_checkpoint(self, epoch, train=True, suffix=''): 164 | self.logger.info('Load checkpoint of epoch %d' % (epoch)) 165 | 166 | for key, net in self.networks.items(): # Load networks 167 | if self.optim_params[key] == None: continue 168 | self.load_network(key, epoch,suffix) 169 | 170 | if train: # initialize and load optimizers 171 | self.init_all_optimizers() 172 | for key, net in self.networks.items(): 173 | if self.optim_params[key] == None: continue 174 | self.load_optimizer(key, epoch,suffix) 175 | 176 | self.curr_epoch = epoch 177 | 178 | def delete_checkpoint(self, epoch, suffix=''): 179 | for key, net in self.networks.items(): 180 | if self.optimizers[key] == None: continue 181 | 182 | filename_net = self._get_net_checkpoint_filename(key, epoch)+suffix 183 | if os.path.isfile(filename_net): os.remove(filename_net) 184 | 185 | filename_optim = self._get_optim_checkpoint_filename(key, epoch)+suffix 186 | if os.path.isfile(filename_optim): os.remove(filename_optim) 187 | 188 | def save_network(self, net_key, epoch, suffix=''): 189 | assert(net_key in self.networks) 190 | filename = self._get_net_checkpoint_filename(net_key, epoch)+suffix 191 | state = {'epoch': epoch,'network': self.networks[net_key].state_dict()} 192 | torch.save(state, filename) 193 | 194 | def save_optimizer(self, net_key, epoch, suffix=''): 195 | assert(net_key in self.optimizers) 196 | filename = self._get_optim_checkpoint_filename(net_key, epoch)+suffix 197 | state = {'epoch': epoch,'optimizer': self.optimizers[net_key].state_dict()} 198 | torch.save(state, filename) 199 | 200 | def load_network(self, net_key, epoch,suffix=''): 201 | assert(net_key in self.networks) 202 | filename = self._get_net_checkpoint_filename(net_key, epoch)+suffix 203 | assert(os.path.isfile(filename)) 204 | if os.path.isfile(filename): 205 | checkpoint = torch.load(filename) 206 | self.networks[net_key].load_state_dict(checkpoint['network']) 207 | 208 | def load_optimizer(self, net_key, epoch,suffix=''): 209 | assert(net_key in self.optimizers) 210 | filename = self._get_optim_checkpoint_filename(net_key, epoch)+suffix 211 | assert(os.path.isfile(filename)) 212 | if os.path.isfile(filename): 213 | checkpoint = torch.load(filename) 214 | self.optimizers[net_key].load_state_dict(checkpoint['optimizer']) 215 | 216 | def _get_net_checkpoint_filename(self, net_key, epoch): 217 | return os.path.join(self.exp_dir, net_key+'_net_epoch'+str(epoch)) 218 | 219 | def _get_optim_checkpoint_filename(self, net_key, epoch): 220 | return os.path.join(self.exp_dir, net_key+'_optim_epoch'+str(epoch)) 221 | 222 | def solve(self, data_loader_train, data_loader_test): 223 | self.max_num_epochs = self.opt['max_num_epochs'] 224 | start_epoch = self.curr_epoch 225 | if len(self.optimizers) == 0: 226 | self.init_all_optimizers() 227 | 228 | eval_stats = {} 229 | train_stats = {} 230 | self.init_record_of_best_model() 231 | for self.curr_epoch in xrange(start_epoch, self.max_num_epochs): 232 | self.logger.info('Training epoch [%3d / %3d]' % (self.curr_epoch+1, self.max_num_epochs)) 233 | self.adjust_learning_rates(self.curr_epoch) 234 | train_stats = self.run_train_epoch(data_loader_train, self.curr_epoch) 235 | self.logger.info('==> Training stats: %s' % (train_stats)) 236 | 237 | self.save_checkpoint(self.curr_epoch+1) # create a checkpoint in the current epoch 238 | if start_epoch != self.curr_epoch: # delete the checkpoint of the previous epoch 239 | self.delete_checkpoint(self.curr_epoch) 240 | 241 | if data_loader_test is not None: 242 | eval_stats = self.evaluate(data_loader_test) 243 | self.logger.info('==> Evaluation stats: %s' % (eval_stats)) 244 | self.keep_record_of_best_model(eval_stats, self.curr_epoch) 245 | 246 | self.print_eval_stats_of_best_model() 247 | 248 | def run_train_epoch(self, data_loader, epoch): 249 | self.logger.info('Training: %s' % os.path.basename(self.exp_dir)) 250 | self.dloader = data_loader 251 | self.dataset_train = data_loader.dataset 252 | 253 | for key, network in self.networks.items(): 254 | if self.optimizers[key] == None: network.eval() 255 | else: network.train() 256 | 257 | disp_step = self.opt['disp_step'] if ('disp_step' in self.opt) else 50 258 | train_stats = utils.DAverageMeter() 259 | self.bnumber = len(data_loader()) 260 | for idx, batch in enumerate(tqdm(data_loader(epoch))): 261 | self.biter = idx 262 | train_stats_this = self.train_step(batch) 263 | train_stats.update(train_stats_this) 264 | if (idx+1) % disp_step == 0: 265 | self.logger.info('==> Iteration [%3d][%4d / %4d]: %s' % (epoch+1, idx+1, len(data_loader), train_stats.average())) 266 | 267 | return train_stats.average() 268 | 269 | def evaluate(self, dloader): 270 | self.logger.info('Evaluating: %s' % os.path.basename(self.exp_dir)) 271 | 272 | self.dloader = dloader 273 | self.dataset_eval = dloader.dataset 274 | self.logger.info('==> Dataset: %s [%d images]' % (dloader.dataset.name, len(dloader))) 275 | for key, network in self.networks.items(): 276 | network.eval() 277 | 278 | eval_stats = utils.DAverageMeter() 279 | self.bnumber = len(dloader()) 280 | for idx, batch in enumerate(tqdm(dloader())): 281 | self.biter = idx 282 | eval_stats_this = self.evaluation_step(batch) 283 | eval_stats.update(eval_stats_this) 284 | 285 | self.logger.info('==> Results: %s' % eval_stats.average()) 286 | 287 | return eval_stats.average() 288 | 289 | def adjust_learning_rates(self, epoch): 290 | # filter out the networks that are not trainable and that do 291 | # not have a learning rate Look Up Table (LUT_lr) in their optim_params 292 | optim_params_filtered = {k:v for k,v in self.optim_params.items() 293 | if (v != None and ('LUT_lr' in v))} 294 | 295 | for key, oparams in optim_params_filtered.items(): 296 | LUT = oparams['LUT_lr'] 297 | lr = next((lr for (max_epoch, lr) in LUT if max_epoch>epoch), LUT[-1][1]) 298 | self.logger.info('==> Set to %s optimizer lr = %.10f' % (key, lr)) 299 | for param_group in self.optimizers[key].param_groups: 300 | param_group['lr'] = lr 301 | 302 | def init_record_of_best_model(self): 303 | self.max_metric_val = None 304 | self.best_stats = None 305 | self.best_epoch = None 306 | 307 | def keep_record_of_best_model(self, eval_stats, current_epoch): 308 | if self.keep_best_model_metric_name is not None: 309 | metric_name = self.keep_best_model_metric_name 310 | if (metric_name not in eval_stats): 311 | raise ValueError('The provided metric {0} for keeping the best model is not computed by the evaluation routine.'.format(metric_name)) 312 | metric_val = eval_stats[metric_name] 313 | if self.max_metric_val is None or metric_val > self.max_metric_val: 314 | self.max_metric_val = metric_val 315 | self.best_stats = eval_stats 316 | self.save_checkpoint(self.curr_epoch+1, suffix='.best') 317 | if self.best_epoch is not None: 318 | self.delete_checkpoint(self.best_epoch+1, suffix='.best') 319 | self.best_epoch = current_epoch 320 | self.print_eval_stats_of_best_model() 321 | 322 | def print_eval_stats_of_best_model(self): 323 | if self.best_stats is not None: 324 | metric_name = self.keep_best_model_metric_name 325 | self.logger.info('==> Best results w.r.t. %s metric: epoch: %d - %s' % (metric_name, self.best_epoch+1, self.best_stats)) 326 | 327 | 328 | # FROM HERE ON ARE ABSTRACT FUNCTIONS THAT MUST BE IMPLEMENTED BY THE CLASS 329 | # THAT INHERITS THE Algorithms CLASS 330 | def train_step(self, batch): 331 | """Implements a training step that includes: 332 | * Forward a batch through the network(s) 333 | * Compute loss(es) 334 | * Backward propagation through the networks 335 | * Apply optimization step(s) 336 | * Return a dictionary with the computed losses and any other desired 337 | stats. The key names on the dictionary can be arbitrary. 338 | """ 339 | pass 340 | 341 | def evaluation_step(self, batch): 342 | """Implements an evaluation step that includes: 343 | * Forward a batch through the network(s) 344 | * Compute loss(es) or any other evaluation metrics. 345 | * Return a dictionary with the computed losses the evaluation 346 | metrics for that batch. The key names on the dictionary can be 347 | arbitrary. 348 | """ 349 | pass 350 | 351 | def allocate_tensors(self): 352 | """(Optional) allocate torch tensors that could potentially be used in 353 | in the train_step() or evaluation_step() functions. If the 354 | load_to_gpu() function is called then those tensors will be moved to 355 | the gpu device. 356 | """ 357 | self.tensors = {} 358 | -------------------------------------------------------------------------------- /ImageNet/algorithms/FeatureClassificationModel.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.autograd import Variable 3 | import utils 4 | import time 5 | 6 | from . import Algorithm 7 | from pdb import set_trace as breakpoint 8 | 9 | 10 | def accuracy(output, target, topk=(1,)): 11 | """Computes the precision@k for the specified values of k""" 12 | maxk = max(topk) 13 | batch_size = target.size(0) 14 | 15 | _, pred = output.topk(maxk, 1, True, True) 16 | pred = pred.t() 17 | correct = pred.eq(target.view(1, -1).expand_as(pred)) 18 | 19 | res = [] 20 | for k in topk: 21 | correct_k = correct[:k].view(-1).float().sum(0) 22 | res.append(correct_k.mul_(100.0 / batch_size)) 23 | return res 24 | 25 | class FeatureClassificationModel(Algorithm): 26 | def __init__(self, opt): 27 | self.out_feat_keys = opt['out_feat_keys'] 28 | Algorithm.__init__(self, opt) 29 | 30 | def allocate_tensors(self): 31 | self.tensors = {} 32 | self.tensors['dataX'] = torch.FloatTensor() 33 | self.tensors['labels'] = torch.LongTensor() 34 | 35 | def train_step(self, batch): 36 | return self.process_batch(batch, do_train=True) 37 | 38 | def evaluation_step(self, batch): 39 | return self.process_batch(batch, do_train=False) 40 | 41 | def process_batch(self, batch, do_train=True): 42 | #*************** LOAD BATCH (AND MOVE IT TO GPU) ******** 43 | start = time.time() 44 | self.tensors['dataX'].resize_(batch[0].size()).copy_(batch[0]) 45 | self.tensors['labels'].resize_(batch[1].size()).copy_(batch[1]) 46 | dataX = self.tensors['dataX'] 47 | labels = self.tensors['labels'] 48 | batch_load_time = time.time() - start 49 | #******************************************************** 50 | 51 | #******************************************************** 52 | start = time.time() 53 | out_feat_keys = self.out_feat_keys 54 | finetune_feat_extractor = self.optimizers['feat_extractor'] is not None 55 | if do_train: # zero the gradients 56 | self.optimizers['classifier'].zero_grad() 57 | if finetune_feat_extractor: 58 | self.optimizers['feat_extractor'].zero_grad() 59 | else: 60 | self.networks['feat_extractor'].eval() 61 | #******************************************************** 62 | 63 | #***************** SET TORCH VARIABLES ****************** 64 | dataX_var = Variable(dataX, volatile=((not do_train) or (not finetune_feat_extractor))) 65 | labels_var = Variable(labels, requires_grad=False) 66 | #******************************************************** 67 | 68 | #************ FORWARD PROPAGATION *********************** 69 | feat_var, feat_var_ = self.networks['feat_extractor'](dataX_var, dataX_var, out_feat_keys=out_feat_keys) 70 | if not finetune_feat_extractor: 71 | if isinstance(feat_var, (list, tuple)): 72 | for i in range(len(feat_var)): 73 | feat_var[i] = Variable(feat_var[i].data, volatile=(not do_train)) 74 | else: 75 | feat_var = Variable(feat_var.data, volatile=(not do_train)) 76 | pred_var = self.networks['classifier'](feat_var) 77 | #******************************************************** 78 | 79 | #*************** COMPUTE LOSSES ************************* 80 | record = {} 81 | if isinstance(pred_var, (list, tuple)): 82 | loss_total = None 83 | for i in range(len(pred_var)): 84 | loss_this = self.criterions['loss'](pred_var[i], labels_var) 85 | loss_total = loss_this if (loss_total is None) else (loss_total + loss_this) 86 | record['prec1_c'+str(1+i)] = accuracy(pred_var[i].data, labels, topk=(1,))[0].item() 87 | record['prec5_c'+str(1+i)] = accuracy(pred_var[i].data, labels, topk=(5,))[0].item() 88 | else: 89 | loss_total = self.criterions['loss'](pred_var, labels_var) 90 | record['prec1'] = accuracy(pred_var.data, labels, topk=(1,))[0].item() 91 | record['prec5'] = accuracy(pred_var.data, labels, topk=(5,))[0].item() 92 | record['loss'] = loss_total.item() 93 | #******************************************************** 94 | 95 | #****** BACKPROPAGATE AND APPLY OPTIMIZATION STEP ******* 96 | if do_train: 97 | loss_total.backward() 98 | self.optimizers['classifier'].step() 99 | if finetune_feat_extractor: 100 | self.optimizers['feat_extractor'].step() 101 | #******************************************************** 102 | batch_process_time = time.time() - start 103 | total_time = batch_process_time + batch_load_time 104 | record['load_time'] = 100*(batch_load_time/total_time) 105 | record['process_time'] = 100*(batch_process_time/total_time) 106 | 107 | return record 108 | -------------------------------------------------------------------------------- /ImageNet/algorithms/UnsupervisedModel.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import numpy as np 3 | 4 | import torch 5 | import torch.nn as nn 6 | import torch.nn.parallel 7 | import torch.optim 8 | import os 9 | import torchnet as tnt 10 | import utils 11 | import PIL 12 | import pickle 13 | from tqdm import tqdm 14 | import time 15 | 16 | from . import Algorithm 17 | from pdb import set_trace as breakpoint 18 | 19 | 20 | def accuracy(output, target, topk=(1,)): 21 | """Computes the precision@k for the specified values of k""" 22 | maxk = max(topk) 23 | batch_size = target.size(0) 24 | 25 | _, pred = output.topk(maxk, 1, True, True) 26 | pred = pred.t() 27 | correct = pred.eq(target.view(1, -1).expand_as(pred)) 28 | 29 | res = [] 30 | for k in topk: 31 | correct_k = correct[:k].view(-1).float().sum(0) 32 | res.append(correct_k.mul_(100.0 / batch_size)) 33 | return res 34 | 35 | class UnsupervisedModel(Algorithm): 36 | def __init__(self, opt): 37 | Algorithm.__init__(self, opt) 38 | 39 | def allocate_tensors(self): 40 | self.tensors = {} 41 | self.tensors['dataX'] = torch.FloatTensor() 42 | self.tensors['dataY'] = torch.FloatTensor() 43 | self.tensors['labels'] = torch.FloatTensor() 44 | 45 | def train_step(self, batch): 46 | return self.process_batch(batch, do_train=True) 47 | 48 | def evaluation_step(self, batch): 49 | return self.process_batch(batch, do_train=False) 50 | 51 | def process_batch(self, batch, do_train=True): 52 | #*************** LOAD BATCH (AND MOVE IT TO GPU) ******** 53 | start = time.time() 54 | self.tensors['dataX'].resize_(batch[0].size()).copy_(batch[0]) 55 | self.tensors['dataY'].resize_(batch[1].size()).copy_(batch[1]) 56 | self.tensors['labels'].resize_(batch[2].size()).copy_(batch[2]) 57 | dataX = self.tensors['dataX'] 58 | dataY = self.tensors['dataY'] 59 | labels = self.tensors['labels'] 60 | batch_load_time = time.time() - start 61 | #******************************************************** 62 | 63 | #******************************************************** 64 | start = time.time() 65 | if do_train: # zero the gradients 66 | self.optimizers['model'].zero_grad() 67 | #******************************************************** 68 | 69 | #***************** SET TORCH VARIABLES ****************** 70 | dataX_var = torch.autograd.Variable(dataX, volatile=(not do_train)) 71 | dataY_var = torch.autograd.Variable(dataY, volatile=(not do_train)) 72 | labels_var = torch.autograd.Variable(labels, requires_grad=False) 73 | #******************************************************** 74 | 75 | #************ FORWARD THROUGH NET *********************** 76 | f1, f2, output_mu, output_logvar = self.networks['model'](dataX_var, dataY_var) 77 | output_logvar = output_logvar / 1000. 78 | std_sqr = torch.exp(output_logvar) 79 | batch_size = dataX_var.size(0) 80 | #******************************************************** 81 | 82 | #*************** COMPUTE LOSSES ************************* 83 | record = {} 84 | loss_total = (torch.sum(output_logvar) + torch.sum((output_mu - labels_var)*(output_mu - labels_var) / (std_sqr + 1e-4))) / batch_size 85 | record['loss'] = loss_total.item() 86 | loss_matrix = self.criterions['loss'](output_mu, labels_var) 87 | record['loss_matrix'] = loss_matrix.item() 88 | #******************************************************** 89 | 90 | #****** BACKPROPAGATE AND APPLY OPTIMIZATION STEP ******* 91 | if do_train: 92 | loss_total.backward() 93 | self.optimizers['model'].step() 94 | #******************************************************** 95 | batch_process_time = time.time() - start 96 | total_time = batch_process_time + batch_load_time 97 | record['load_time'] = 100*(batch_load_time/total_time) 98 | record['process_time'] = 100*(batch_process_time/total_time) 99 | 100 | return record 101 | -------------------------------------------------------------------------------- /ImageNet/algorithms/__init__.py: -------------------------------------------------------------------------------- 1 | from .Algorithm import * 2 | from .UnsupervisedModel import UnsupervisedModel 3 | from .FeatureClassificationModel import FeatureClassificationModel 4 | -------------------------------------------------------------------------------- /ImageNet/architectures/AlexNet.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | import numpy as np 6 | 7 | from pdb import set_trace as breakpoint 8 | 9 | class Flatten(nn.Module): 10 | def __init__(self): 11 | super(Flatten, self).__init__() 12 | 13 | def forward(self, feat): 14 | return feat.view(feat.size(0), -1) 15 | 16 | class EncBlock(nn.Module): 17 | def __init__(self, in_planes, out_planes, kernel_size): 18 | super(EncBlock, self).__init__() 19 | padding = (kernel_size-1)/2 20 | self.layers = nn.Sequential() 21 | self.layers.add_module('Conv', nn.Conv2d(in_planes, out_planes, \ 22 | kernel_size=kernel_size, stride=1, padding=padding, bias=False)) 23 | self.layers.add_module('BatchNorm', nn.BatchNorm2d(out_planes)) 24 | 25 | def forward(self, x): 26 | out = self.layers(x) 27 | return torch.cat([x,out], dim=1) 28 | 29 | class AlexNet(nn.Module): 30 | def __init__(self): 31 | super(AlexNet, self).__init__() 32 | 33 | conv1 = nn.Sequential( 34 | nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2), 35 | nn.BatchNorm2d(64), 36 | nn.ReLU(inplace=True), 37 | ) 38 | pool1 = nn.MaxPool2d(kernel_size=3, stride=2) 39 | conv2 = nn.Sequential( 40 | nn.Conv2d(64, 192, kernel_size=5, padding=2), 41 | nn.BatchNorm2d(192), 42 | nn.ReLU(inplace=True), 43 | ) 44 | pool2 = nn.MaxPool2d(kernel_size=3, stride=2) 45 | conv3 = nn.Sequential( 46 | nn.Conv2d(192, 384, kernel_size=3, padding=1), 47 | nn.BatchNorm2d(384), 48 | nn.ReLU(inplace=True), 49 | ) 50 | conv4 = nn.Sequential( 51 | nn.Conv2d(384, 256, kernel_size=3, padding=1), 52 | nn.BatchNorm2d(256), 53 | nn.ReLU(inplace=True), 54 | EncBlock(256,256,1), 55 | ) 56 | conv5 = nn.Sequential( 57 | nn.Conv2d(256, 256, kernel_size=3, padding=1), 58 | nn.BatchNorm2d(256), 59 | nn.ReLU(inplace=True), 60 | ) 61 | pool5 = nn.MaxPool2d(kernel_size=3, stride=2) 62 | 63 | num_pool5_feats = 6 * 6 * 256 64 | fc_block = nn.Sequential( 65 | Flatten(), 66 | nn.Linear(num_pool5_feats, 4096, bias=False), 67 | nn.BatchNorm1d(4096), 68 | nn.ReLU(inplace=True), 69 | nn.Linear(4096, 4096, bias=False), 70 | nn.BatchNorm1d(4096), 71 | nn.ReLU(inplace=True), 72 | ) 73 | 74 | self._feature_blocks = nn.ModuleList([ 75 | conv1, 76 | pool1, 77 | conv2, 78 | pool2, 79 | conv3, 80 | conv4, 81 | conv5, 82 | pool5, 83 | fc_block, 84 | ]) 85 | self.all_feat_names = [ 86 | 'conv1', 87 | 'pool1', 88 | 'conv2', 89 | 'pool2', 90 | 'conv3', 91 | 'conv4', 92 | 'conv5', 93 | 'pool5', 94 | 'fc_block', 95 | ] 96 | assert(len(self.all_feat_names) == len(self._feature_blocks)) 97 | 98 | def _parse_out_keys_arg(self, out_feat_keys): 99 | 100 | # By default return the features of the last layer / module. 101 | out_feat_keys = [self.all_feat_names[-1],] if out_feat_keys is None else out_feat_keys 102 | 103 | if len(out_feat_keys) == 0: 104 | raise ValueError('Empty list of output feature keys.') 105 | for f, key in enumerate(out_feat_keys): 106 | if key not in self.all_feat_names: 107 | raise ValueError('Feature with name {0} does not exist. Existing features: {1}.'.format(key, self.all_feat_names)) 108 | elif key in out_feat_keys[:f]: 109 | raise ValueError('Duplicate output feature key: {0}.'.format(key)) 110 | 111 | # Find the highest output feature in `out_feat_keys 112 | max_out_feat = max([self.all_feat_names.index(key) for key in out_feat_keys]) 113 | 114 | return out_feat_keys, max_out_feat 115 | 116 | def forward(self, x, out_feat_keys=None): 117 | """Forward an image `x` through the network and return the asked output features. 118 | 119 | Args: 120 | x: input image. 121 | out_feat_keys: a list/tuple with the feature names of the features 122 | that the function should return. By default the last feature of 123 | the network is returned. 124 | 125 | Return: 126 | out_feats: If multiple output features were asked then `out_feats` 127 | is a list with the asked output features placed in the same 128 | order as in `out_feat_keys`. If a single output feature was 129 | asked then `out_feats` is that output feature (and not a list). 130 | """ 131 | out_feat_keys, max_out_feat = self._parse_out_keys_arg(out_feat_keys) 132 | out_feats = [None] * len(out_feat_keys) 133 | 134 | feat = x 135 | #encode 136 | for f in range(6): 137 | feat = self._feature_blocks[f](feat) 138 | key = self.all_feat_names[f] 139 | if key in out_feat_keys: 140 | out_feats[out_feat_keys.index(key)] = feat 141 | 142 | #reparameterize 143 | mu = feat[:,:256] 144 | logvar = feat[:, 256:] 145 | std = torch.exp(0.5*logvar) 146 | 147 | eps = torch.randn_like(std) 148 | feat = eps.mul(std * 0.001).add_(mu) 149 | 150 | #decode 151 | if max_out_feat >= 5: 152 | for f in range(6, max_out_feat+1): 153 | feat = self._feature_blocks[f](feat) 154 | key = self.all_feat_names[f] 155 | if key in out_feat_keys: 156 | out_feats[out_feat_keys.index(key)] = feat 157 | 158 | out_feats = out_feats[0] if len(out_feats)==1 else out_feats 159 | return out_feats 160 | 161 | def get_L1filters(self): 162 | convlayer = self._feature_blocks[0][0] 163 | batchnorm = self._feature_blocks[0][1] 164 | filters = convlayer.weight.data 165 | scalars = (batchnorm.weight.data / torch.sqrt(batchnorm.running_var + 1e-05)) 166 | filters = (filters * scalars.view(-1, 1, 1, 1).expand_as(filters)).cpu().clone() 167 | 168 | return filters 169 | 170 | class Regressor(nn.Module): 171 | def __init__(self, opt, indim=4096*2): 172 | super(Regressor, self).__init__() 173 | num_classes = opt['num_classes'] 174 | self.Alexnet = AlexNet() 175 | 176 | self.fc = nn.Linear(indim, num_classes) 177 | self.fc2 = nn.Linear(indim, num_classes) 178 | 179 | def forward(self, x1, x2, out_feat_keys=None): 180 | x1 = self.Alexnet(x1, out_feat_keys) 181 | x2 = self.Alexnet(x2, out_feat_keys) 182 | if out_feat_keys==None: 183 | x = torch.cat((x1,x2), dim=1) 184 | return x1, x2, self.fc(x), self.fc2(x) 185 | else: 186 | return x1, x2 187 | 188 | def create_model(opt): 189 | return Regressor(opt) 190 | 191 | if __name__ == '__main__': 192 | size = 224 193 | opt = {'num_classes':4} 194 | 195 | net = create_model(opt) 196 | x = torch.autograd.Variable(torch.FloatTensor(1,3,size,size).uniform_(-1,1)) 197 | 198 | out = net(x, out_feat_keys=net.all_feat_names) 199 | for f in range(len(out)): 200 | print('Output feature {0} - size {1}'.format( 201 | net.all_feat_names[f], out[f].size())) 202 | 203 | filters = net.get_L1filters() 204 | 205 | print('First layer filter shape: {0}'.format(filters.size())) 206 | -------------------------------------------------------------------------------- /ImageNet/architectures/LinearClassifier.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | import numpy as np 6 | 7 | class Flatten(nn.Module): 8 | def __init__(self): 9 | super(Flatten, self).__init__() 10 | 11 | def forward(self, feat): 12 | return feat.view(feat.size(0), -1) 13 | 14 | class Classifier(nn.Module): 15 | def __init__(self, opt): 16 | super(Classifier, self).__init__() 17 | nChannels = opt['nChannels'] 18 | num_classes = opt['num_classes'] 19 | pool_size = opt['pool_size'] 20 | pool_type = opt['pool_type'] if ('pool_type' in opt) else 'max' 21 | nChannelsAll = nChannels * pool_size * pool_size 22 | 23 | self.classifier = nn.Sequential() 24 | if pool_type == 'max': 25 | self.classifier.add_module('MaxPool', nn.AdaptiveMaxPool2d((pool_size, pool_size))) 26 | elif pool_type == 'avg': 27 | self.classifier.add_module('AvgPool', nn.AdaptiveAvgPool2d((pool_size, pool_size))) 28 | self.classifier.add_module('BatchNorm', nn.BatchNorm2d(nChannels, affine=False)) 29 | self.classifier.add_module('Flatten', Flatten()) 30 | self.classifier.add_module('LiniearClassifier', nn.Linear(nChannelsAll, num_classes)) 31 | self.initilize() 32 | 33 | def forward(self, feat): 34 | return self.classifier(feat) 35 | 36 | def initilize(self): 37 | for m in self.modules(): 38 | if isinstance(m, nn.Linear): 39 | fin = m.in_features 40 | fout = m.out_features 41 | std_val = np.sqrt(2.0/fout) 42 | m.weight.data.normal_(0.0, std_val) 43 | if m.bias is not None: 44 | m.bias.data.fill_(0.0) 45 | 46 | def create_model(opt): 47 | return Classifier(opt) 48 | -------------------------------------------------------------------------------- /ImageNet/architectures/MultipleLinearClassifiers.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import imp 4 | import os 5 | 6 | 7 | current_path = os.path.abspath(__file__) 8 | filepath_to_linear_classifier_definition = os.path.join(os.path.dirname(current_path), 'LinearClassifier.py') 9 | LinearClassifier = imp.load_source('',filepath_to_linear_classifier_definition).create_model 10 | 11 | 12 | class MClassifier(nn.Module): 13 | def __init__(self, opts): 14 | super(MClassifier, self).__init__() 15 | self.classifiers = nn.ModuleList([LinearClassifier(opt) for opt in opts]) 16 | self.num_classifiers = len(opts) 17 | 18 | 19 | def forward(self, feats): 20 | assert(len(feats) == self.num_classifiers) 21 | outputs = [] 22 | for i, feat in enumerate(feats): 23 | if i == 3: 24 | out_mean = feat[:, :256] 25 | out_var = feat[:, 256:] 26 | std = torch.exp(0.5*out_var) 27 | feats = [] 28 | for _ in range(5): 29 | eps = torch.randn_like(std) 30 | feat = eps.mul(std * 0.001).add_(out_mean) 31 | feats.append(feat) 32 | 33 | feat = feats[0] 34 | for ii in range(1, 5): 35 | feat += feats[ii] 36 | 37 | feat = feat / 5. 38 | 39 | outputs = outputs + [self.classifiers[i](feat)] 40 | return outputs 41 | 42 | def create_model(opt): 43 | return MClassifier(opt) 44 | 45 | -------------------------------------------------------------------------------- /ImageNet/architectures/MultipleNonLinearClassifiers.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import imp 4 | import os 5 | 6 | 7 | current_path = os.path.abspath(__file__) 8 | filepath_to_classifier_definition = os.path.join(os.path.dirname(current_path), 'NonLinearClassifier.py') 9 | NonLinearClassifier = imp.load_source('',filepath_to_classifier_definition).create_model 10 | 11 | 12 | class MClassifier(nn.Module): 13 | def __init__(self, opts): 14 | super(MClassifier, self).__init__() 15 | self.classifiers = nn.ModuleList([NonLinearClassifier(opt) for opt in opts]) 16 | self.num_classifiers = len(opts) 17 | 18 | 19 | def forward(self, feats): 20 | assert(len(feats) == self.num_classifiers) 21 | return [self.classifiers[i](feat) for i, feat in enumerate(feats)] 22 | 23 | 24 | def create_model(opt): 25 | return MClassifier(opt) 26 | -------------------------------------------------------------------------------- /ImageNet/architectures/NonLinearClassifier.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | import numpy as np 6 | 7 | class BasicBlock(nn.Module): 8 | def __init__(self, in_planes, out_planes, kernel_size, stride=1): 9 | super(BasicBlock, self).__init__() 10 | padding = (kernel_size-1)/2 11 | self.layers = nn.Sequential() 12 | self.layers.add_module('Conv', nn.Conv2d(in_planes, out_planes, \ 13 | kernel_size=kernel_size, stride=stride, padding=padding, bias=False)) 14 | self.layers.add_module('BatchNorm', nn.BatchNorm2d(out_planes)) 15 | self.layers.add_module('ReLU', nn.ReLU(inplace=True)) 16 | 17 | def forward(self, x): 18 | return self.layers(x) 19 | 20 | class GlobalAvgPool(nn.Module): 21 | def __init__(self): 22 | super(GlobalAvgPool, self).__init__() 23 | 24 | def forward(self, feat): 25 | assert(feat.size(2) == feat.size(3)) 26 | feat_avg = F.avg_pool2d(feat, feat.size(2)).view(-1, feat.size(1)) 27 | return feat_avg 28 | 29 | class Flatten(nn.Module): 30 | def __init__(self): 31 | super(Flatten, self).__init__() 32 | 33 | def forward(self, feat): 34 | return feat.view(feat.size(0), -1) 35 | 36 | class Classifier(nn.Module): 37 | def __init__(self, opt): 38 | super(Classifier, self).__init__() 39 | nChannels = opt['nChannels'] 40 | num_classes = opt['num_classes'] 41 | self.cls_type = opt['cls_type'] 42 | 43 | self.classifier = nn.Sequential() 44 | 45 | if self.cls_type == 'Alexnet_conv5' or self.cls_type == 'Alexnet_conv4': 46 | if self.cls_type == 'Alexnet_conv4': 47 | block5 = nn.Sequential( 48 | nn.Conv2d(256, 256, kernel_size=3, padding=1), 49 | nn.BatchNorm2d(256), 50 | nn.ReLU(inplace=True), 51 | ) 52 | self.classifier.add_module('ConvB5', block5) 53 | self.classifier.add_module('Pool5', nn.MaxPool2d(kernel_size=3, stride=2)) 54 | self.classifier.add_module('Flatten', Flatten()) 55 | self.classifier.add_module('Linear1', nn.Linear(256*6*6, 4096, bias=False)) 56 | self.classifier.add_module('BatchNorm1', nn.BatchNorm1d(4096)) 57 | self.classifier.add_module('ReLU1', nn.ReLU(inplace=True)) 58 | self.classifier.add_module('Liniear2', nn.Linear(4096, 4096, bias=False)) 59 | self.classifier.add_module('BatchNorm2', nn.BatchNorm1d(4096)) 60 | self.classifier.add_module('ReLU2', nn.ReLU(inplace=True)) 61 | self.classifier.add_module('LinearF', nn.Linear(4096, num_classes)) 62 | else: 63 | raise ValueError('Not recognized classifier type: %s' % self.cls_type) 64 | 65 | self.initilize() 66 | 67 | def forward(self, feat): 68 | if self.cls_type == 'Alexnet_conv4': 69 | out_mean = feat[:, :256] 70 | out_var = feat[:, 256:] 71 | std = torch.exp(0.5*out_var) 72 | 73 | feats = [] 74 | for _ in range(5): 75 | eps = torch.randn_like(std) 76 | feat = eps.mul(std * 0.001).add_(out_mean) 77 | feats.append(feat) 78 | 79 | feat = feats[0] 80 | for ii in range(1, 5): 81 | feat += feats[ii] 82 | 83 | feat = feat / 5. 84 | return self.classifier(feat) 85 | else: 86 | return self.classifier(feat) 87 | 88 | def initilize(self): 89 | for m in self.modules(): 90 | if isinstance(m, nn.Conv2d): 91 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 92 | m.weight.data.normal_(0, math.sqrt(2. / n)) 93 | elif isinstance(m, nn.BatchNorm2d): 94 | m.weight.data.fill_(1) 95 | m.bias.data.zero_() 96 | elif isinstance(m, nn.Linear): 97 | fin = m.in_features 98 | fout = m.out_features 99 | std_val = np.sqrt(2.0/fout) 100 | m.weight.data.normal_(0.0, std_val) 101 | if m.bias is not None: 102 | m.bias.data.fill_(0.0) 103 | 104 | def create_model(opt): 105 | return Classifier(opt) 106 | -------------------------------------------------------------------------------- /ImageNet/config/ImageNet_LinearClassifiers_Avgpooling.py: -------------------------------------------------------------------------------- 1 | batch_size = 192 2 | 3 | config = {} 4 | # set the parameters related to the training and testing set 5 | data_train_opt = {} 6 | data_train_opt['batch_size'] = batch_size 7 | data_train_opt['unsupervised'] = False 8 | data_train_opt['epoch_size'] = None 9 | data_train_opt['random_sized_crop'] = False 10 | data_train_opt['dataset_name'] = 'imagenet' 11 | data_train_opt['split'] = 'train' 12 | 13 | data_test_opt = {} 14 | data_test_opt['batch_size'] = batch_size 15 | data_test_opt['unsupervised'] = False 16 | data_test_opt['epoch_size'] = None 17 | data_test_opt['random_sized_crop'] = False 18 | data_test_opt['dataset_name'] = 'imagenet' 19 | data_test_opt['split'] = 'val' 20 | 21 | config['data_train_opt'] = data_train_opt 22 | config['data_test_opt'] = data_test_opt 23 | config['max_num_epochs'] = 65 24 | 25 | 26 | networks = {} 27 | 28 | pretrained = './experiments/ImageNet_Unsupervised/model_net_epoch400' 29 | networks['feat_extractor'] = {'def_file': 'architectures/AlexNet.py', 'pretrained': pretrained, 'opt': {'num_classes': 8}, 'optim_params': None} 30 | 31 | net_opt_cls = [None] * 5 32 | net_opt_cls[0] = {'pool_type':'avg', 'nChannels':64, 'pool_size':12, 'num_classes': 1000} 33 | net_opt_cls[1] = {'pool_type':'avg', 'nChannels':192, 'pool_size':7, 'num_classes': 1000} 34 | net_opt_cls[2] = {'pool_type':'avg', 'nChannels':384, 'pool_size':5, 'num_classes': 1000} 35 | net_opt_cls[3] = {'pool_type':'avg', 'nChannels':256, 'pool_size':6, 'num_classes': 1000} 36 | net_opt_cls[4] = {'pool_type':'avg', 'nChannels':256, 'pool_size':6, 'num_classes': 1000} 37 | out_feat_keys = ['conv1', 'conv2', 'conv3', 'conv4', 'conv5'] 38 | net_optim_params_cls = {'optim_type': 'sgd', 'lr': 0.1, 'momentum':0.9, 'weight_decay': 5e-4, 'nesterov': True, 'LUT_lr':[(5, 0.01),(25, 0.002),(45, 0.0004),(65, 0.00008)]} 39 | networks['classifier'] = {'def_file': 'architectures/MultipleLinearClassifiers.py', 'pretrained': None, 'opt': net_opt_cls, 'optim_params': net_optim_params_cls} 40 | 41 | config['networks'] = networks 42 | 43 | criterions = {} 44 | criterions['loss'] = {'ctype':'CrossEntropyLoss', 'opt':None} 45 | config['criterions'] = criterions 46 | config['algorithm_type'] = 'FeatureClassificationModel' 47 | config['out_feat_keys'] = out_feat_keys 48 | 49 | -------------------------------------------------------------------------------- /ImageNet/config/ImageNet_LinearClassifiers_Maxpooling.py: -------------------------------------------------------------------------------- 1 | batch_size = 192 2 | 3 | config = {} 4 | # set the parameters related to the training and testing set 5 | data_train_opt = {} 6 | data_train_opt['batch_size'] = batch_size 7 | data_train_opt['unsupervised'] = False 8 | data_train_opt['epoch_size'] = None 9 | data_train_opt['random_sized_crop'] = False 10 | data_train_opt['dataset_name'] = 'imagenet' 11 | data_train_opt['split'] = 'train' 12 | 13 | data_test_opt = {} 14 | data_test_opt['batch_size'] = batch_size 15 | data_test_opt['unsupervised'] = False 16 | data_test_opt['epoch_size'] = None 17 | data_test_opt['random_sized_crop'] = False 18 | data_test_opt['dataset_name'] = 'imagenet' 19 | data_test_opt['split'] = 'val' 20 | 21 | config['data_train_opt'] = data_train_opt 22 | config['data_test_opt'] = data_test_opt 23 | config['max_num_epochs'] = 65 24 | 25 | 26 | networks = {} 27 | 28 | pretrained = './experiments/ImageNet_Unsupervised/model_net_epoch400' 29 | networks['feat_extractor'] = {'def_file': 'architectures/AlexNet.py', 'pretrained': pretrained, 'opt': {'num_classes': 8}, 'optim_params': None} 30 | 31 | net_opt_cls = [None] * 5 32 | net_opt_cls[0] = {'pool_type':'max', 'nChannels':64, 'pool_size':12, 'num_classes': 1000} 33 | net_opt_cls[1] = {'pool_type':'max', 'nChannels':192, 'pool_size':7, 'num_classes': 1000} 34 | net_opt_cls[2] = {'pool_type':'max', 'nChannels':384, 'pool_size':5, 'num_classes': 1000} 35 | net_opt_cls[3] = {'pool_type':'max', 'nChannels':256, 'pool_size':6, 'num_classes': 1000} 36 | net_opt_cls[4] = {'pool_type':'max', 'nChannels':256, 'pool_size':6, 'num_classes': 1000} 37 | out_feat_keys = ['conv1', 'conv2', 'conv3', 'conv4', 'conv5'] 38 | net_optim_params_cls = {'optim_type': 'sgd', 'lr': 0.1, 'momentum':0.9, 'weight_decay': 5e-4, 'nesterov': True, 'LUT_lr':[(5, 0.01),(25, 0.002),(45, 0.0004),(65,0.00008)]} 39 | networks['classifier'] = {'def_file': 'architectures/MultipleLinearClassifiers.py', 'pretrained': None, 'opt': net_opt_cls, 'optim_params': net_optim_params_cls} 40 | 41 | config['networks'] = networks 42 | 43 | criterions = {} 44 | criterions['loss'] = {'ctype':'CrossEntropyLoss', 'opt':None} 45 | config['criterions'] = criterions 46 | config['algorithm_type'] = 'FeatureClassificationModel' 47 | config['out_feat_keys'] = out_feat_keys 48 | 49 | -------------------------------------------------------------------------------- /ImageNet/config/ImageNet_NonLinearClassifiers.py: -------------------------------------------------------------------------------- 1 | batch_size = 192 2 | 3 | config = {} 4 | # set the parameters related to the training and testing set 5 | data_train_opt = {} 6 | data_train_opt['batch_size'] = batch_size 7 | data_train_opt['unsupervised'] = False 8 | data_train_opt['epoch_size'] = None 9 | data_train_opt['random_sized_crop'] = False 10 | data_train_opt['dataset_name'] = 'imagenet' 11 | data_train_opt['split'] = 'train' 12 | 13 | data_test_opt = {} 14 | data_test_opt['batch_size'] = batch_size 15 | data_test_opt['unsupervised'] = False 16 | data_test_opt['epoch_size'] = None 17 | data_test_opt['random_sized_crop'] = False 18 | data_test_opt['dataset_name'] = 'imagenet' 19 | data_test_opt['split'] = 'val' 20 | 21 | config['data_train_opt'] = data_train_opt 22 | config['data_test_opt'] = data_test_opt 23 | config['max_num_epochs'] = 50 24 | 25 | 26 | networks = {} 27 | 28 | pretrained = './experiments/ImageNet_Unsupervised/model_net_epoch400' 29 | networks['feat_extractor'] = {'def_file': 'architectures/AlexNet.py', 'pretrained': pretrained, 'opt': {'num_classes': 8}, 'optim_params': None} 30 | 31 | net_opt_cls = [None] * 2 32 | net_opt_cls[0] = {'cls_type':'Alexnet_conv4', 'nChannels':256, 'num_classes':1000} 33 | net_opt_cls[1] = {'cls_type':'Alexnet_conv5', 'nChannels':256, 'num_classes':1000} 34 | out_feat_keys = ['conv4', 'conv5'] 35 | net_optim_params_cls = {'optim_type': 'sgd', 'lr': 0.1, 'momentum':0.9, 'weight_decay': 5e-4, 'nesterov': True, 'LUT_lr':[(20, 0.01),(30, 0.002),(40, 0.0004),(50, 0.00008)]} 36 | networks['classifier'] = {'def_file': 'architectures/MultipleNonLinearClassifiers.py', 'pretrained': None, 'opt': net_opt_cls, 'optim_params': net_optim_params_cls} 37 | 38 | config['networks'] = networks 39 | 40 | criterions = {} 41 | criterions['loss'] = {'ctype':'CrossEntropyLoss', 'opt':None} 42 | config['criterions'] = criterions 43 | config['algorithm_type'] = 'FeatureClassificationModel' 44 | config['out_feat_keys'] = out_feat_keys 45 | -------------------------------------------------------------------------------- /ImageNet/config/ImageNet_Unsupervised.py: -------------------------------------------------------------------------------- 1 | batch_size = 192*4 2 | 3 | config = {} 4 | # set the parameters related to the training and testing set 5 | data_train_opt = {} 6 | data_train_opt['batch_size'] = batch_size 7 | data_train_opt['unsupervised'] = True 8 | data_train_opt['epoch_size'] = None 9 | data_train_opt['random_sized_crop'] = False 10 | data_train_opt['dataset_name'] = 'imagenet' 11 | data_train_opt['split'] = 'train' 12 | 13 | data_test_opt = {} 14 | data_test_opt['batch_size'] = batch_size 15 | data_test_opt['unsupervised'] = True 16 | data_test_opt['epoch_size'] = None 17 | data_test_opt['random_sized_crop'] = False 18 | data_test_opt['dataset_name'] = 'imagenet' 19 | data_test_opt['split'] = 'val' 20 | 21 | config['data_train_opt'] = data_train_opt 22 | config['data_test_opt'] = data_test_opt 23 | config['max_num_epochs'] = 400 24 | 25 | net_opt = {} 26 | net_opt['num_classes'] = 8 27 | net_opt['num_stages'] = 4 28 | 29 | networks = {} 30 | 31 | net_optim_params = {'optim_type': 'sgd', 'lr': 0.001, 'momentum':0.9, 'weight_decay': 5e-4, 'nesterov': True, 'LUT_lr':[(300, 0.001), (350, 0.0001), (400, 0.00001)]} 32 | networks['model'] = {'def_file': 'architectures/AlexNet.py', 'pretrained': None, 'opt': net_opt, 'optim_params': net_optim_params} 33 | config['networks'] = networks 34 | 35 | criterions = {} 36 | criterions['loss'] = {'ctype':'MSELoss', 'opt':True} 37 | config['criterions'] = criterions 38 | config['algorithm_type'] = 'UnsupervisedModel' 39 | -------------------------------------------------------------------------------- /ImageNet/config/Places205_LinearClassifiers_Avgpooling.py: -------------------------------------------------------------------------------- 1 | batch_size = 192 2 | 3 | config = {} 4 | # set the parameters related to the training and testing set 5 | data_train_opt = {} 6 | data_train_opt['batch_size'] = batch_size 7 | data_train_opt['unsupervised'] = False 8 | data_train_opt['epoch_size'] = None 9 | data_train_opt['random_sized_crop'] = False 10 | data_train_opt['dataset_name'] = 'places205' 11 | data_train_opt['split'] = 'train' 12 | 13 | data_test_opt = {} 14 | data_test_opt['batch_size'] = batch_size 15 | data_test_opt['unsupervised'] = False 16 | data_test_opt['epoch_size'] = None 17 | data_test_opt['random_sized_crop'] = False 18 | data_test_opt['dataset_name'] = 'places205' 19 | data_test_opt['split'] = 'val' 20 | 21 | config['data_train_opt'] = data_train_opt 22 | config['data_test_opt'] = data_test_opt 23 | config['max_num_epochs'] = 65 24 | 25 | 26 | networks = {} 27 | 28 | pretrained = './experiments/ImageNet_Unsupervised/model_net_epoch400' 29 | networks['feat_extractor'] = {'def_file': 'architectures/AlexNet.py', 'pretrained': pretrained, 'opt': {'num_classes': 8}, 'optim_params': None} 30 | 31 | net_opt_cls = [None] * 5 32 | net_opt_cls[0] = {'pool_type':'avg', 'nChannels':64, 'pool_size':12, 'num_classes': 205} 33 | net_opt_cls[1] = {'pool_type':'avg', 'nChannels':192, 'pool_size':7, 'num_classes': 205} 34 | net_opt_cls[2] = {'pool_type':'avg', 'nChannels':384, 'pool_size':5, 'num_classes': 205} 35 | net_opt_cls[3] = {'pool_type':'avg', 'nChannels':256, 'pool_size':6, 'num_classes': 205} 36 | net_opt_cls[4] = {'pool_type':'avg', 'nChannels':256, 'pool_size':6, 'num_classes': 205} 37 | out_feat_keys = ['conv1', 'conv2', 'conv3', 'conv4', 'conv5'] 38 | net_optim_params_cls = {'optim_type': 'sgd', 'lr': 0.1, 'momentum':0.9, 'weight_decay': 5e-4, 'nesterov': True, 'LUT_lr':[(5, 0.01),(25, 0.002),(45, 0.0004),(65, 0.00008)]} 39 | networks['classifier'] = {'def_file': 'architectures/MultipleLinearClassifiers.py', 'pretrained': None, 'opt': net_opt_cls, 'optim_params': net_optim_params_cls} 40 | 41 | config['networks'] = networks 42 | 43 | criterions = {} 44 | criterions['loss'] = {'ctype':'CrossEntropyLoss', 'opt':None} 45 | config['criterions'] = criterions 46 | config['algorithm_type'] = 'FeatureClassificationModel' 47 | config['out_feat_keys'] = out_feat_keys 48 | 49 | -------------------------------------------------------------------------------- /ImageNet/config/Places205_LinearClassifiers_Maxpooling.py: -------------------------------------------------------------------------------- 1 | batch_size = 192 2 | 3 | config = {} 4 | # set the parameters related to the training and testing set 5 | data_train_opt = {} 6 | data_train_opt['batch_size'] = batch_size 7 | data_train_opt['unsupervised'] = False 8 | data_train_opt['epoch_size'] = None 9 | data_train_opt['random_sized_crop'] = False 10 | data_train_opt['dataset_name'] = 'places205' 11 | data_train_opt['split'] = 'train' 12 | 13 | data_test_opt = {} 14 | data_test_opt['batch_size'] = batch_size 15 | data_test_opt['unsupervised'] = False 16 | data_test_opt['epoch_size'] = None 17 | data_test_opt['random_sized_crop'] = False 18 | data_test_opt['dataset_name'] = 'places205' 19 | data_test_opt['split'] = 'val' 20 | 21 | config['data_train_opt'] = data_train_opt 22 | config['data_test_opt'] = data_test_opt 23 | config['max_num_epochs'] = 65 24 | 25 | 26 | networks = {} 27 | 28 | pretrained = './experiments/ImageNet_Unsupervised/model_net_epoch400' 29 | networks['feat_extractor'] = {'def_file': 'architectures/AlexNet.py', 'pretrained': pretrained, 'opt': {'num_classes': 8}, 'optim_params': None} 30 | 31 | net_opt_cls = [None] * 5 32 | net_opt_cls[0] = {'pool_type':'max', 'nChannels':64, 'pool_size':12, 'num_classes': 205} 33 | net_opt_cls[1] = {'pool_type':'max', 'nChannels':192, 'pool_size':7, 'num_classes': 205} 34 | net_opt_cls[2] = {'pool_type':'max', 'nChannels':384, 'pool_size':5, 'num_classes': 205} 35 | net_opt_cls[3] = {'pool_type':'max', 'nChannels':256, 'pool_size':6, 'num_classes': 205} 36 | net_opt_cls[4] = {'pool_type':'max', 'nChannels':256, 'pool_size':6, 'num_classes': 205} 37 | out_feat_keys = ['conv1', 'conv2', 'conv3', 'conv4', 'conv5'] 38 | net_optim_params_cls = {'optim_type': 'sgd', 'lr': 0.1, 'momentum':0.9, 'weight_decay': 5e-4, 'nesterov': True, 'LUT_lr':[(5, 0.01),(25, 0.002),(45, 0.0004),(65, 0.00008)]} 39 | networks['classifier'] = {'def_file': 'architectures/MultipleLinearClassifiers.py', 'pretrained': None, 'opt': net_opt_cls, 'optim_params': net_optim_params_cls} 40 | 41 | config['networks'] = networks 42 | 43 | criterions = {} 44 | criterions['loss'] = {'ctype':'CrossEntropyLoss', 'opt':None} 45 | config['criterions'] = criterions 46 | config['algorithm_type'] = 'FeatureClassificationModel' 47 | config['out_feat_keys'] = out_feat_keys 48 | 49 | -------------------------------------------------------------------------------- /ImageNet/dataloader.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import torch 3 | import torch.utils.data as data 4 | import torchvision 5 | import torchnet as tnt 6 | import torchvision.datasets as datasets 7 | import torchvision.transforms as transforms 8 | import torchvision.utils as vutils 9 | import numpy as np 10 | import random 11 | from torch.utils.data.dataloader import default_collate 12 | from PIL import Image, PILLOW_VERSION 13 | import os 14 | import errno 15 | import numpy as np 16 | import sys 17 | import csv 18 | import numbers 19 | import h5py 20 | 21 | from pdb import set_trace as breakpoint 22 | from torchvision.transforms.functional import _get_inverse_affine_matrix 23 | import math 24 | 25 | # Set the paths of the datasets here. 26 | _IMAGENET_DATASET_DIR = '/root/ImageNet' 27 | _PLACES205_DATASET_DIR = '/root/Places205' 28 | 29 | 30 | def buildLabelIndex(labels): 31 | label2inds = {} 32 | for idx, label in enumerate(labels): 33 | if label not in label2inds: 34 | label2inds[label] = [] 35 | label2inds[label].append(idx) 36 | 37 | return label2inds 38 | 39 | class Places205(data.Dataset): 40 | def __init__(self, root, split, transform=None, target_transform=None): 41 | self.root = os.path.expanduser(root) 42 | self.data_folder = os.path.join(self.root, 'data', 'vision', 'torralba', 'deeplearning', 'images256') 43 | self.split_folder = os.path.join(self.root, 'trainvalsplit_places205') 44 | assert(split=='train' or split=='val') 45 | split_csv_file = os.path.join(self.split_folder, split+'_places205.csv') 46 | 47 | self.transform = transform 48 | self.target_transform = target_transform 49 | with open(split_csv_file, 'rb') as f: 50 | reader = csv.reader(f, delimiter=' ') 51 | self.img_files = [] 52 | self.labels = [] 53 | for row in reader: 54 | self.img_files.append(row[0]) 55 | self.labels.append(long(row[1])) 56 | 57 | def __getitem__(self, index): 58 | """ 59 | Args: 60 | index (int): Index 61 | 62 | Returns: 63 | tuple: (image, target) where target is index of the target class. 64 | """ 65 | image_path = os.path.join(self.data_folder, self.img_files[index]) 66 | img = Image.open(image_path).convert('RGB') 67 | target = self.labels[index] 68 | 69 | if self.transform is not None: 70 | img = self.transform(img) 71 | if self.target_transform is not None: 72 | target = self.target_transform(target) 73 | return img, target 74 | 75 | def __len__(self): 76 | return len(self.labels) 77 | 78 | class GenericDataset(data.Dataset): 79 | def __init__(self, dataset_name, split, random_sized_crop=False): 80 | self.split = split.lower() 81 | self.dataset_name = dataset_name.lower() 82 | self.name = self.dataset_name + '_' + self.split 83 | self.random_sized_crop = random_sized_crop 84 | 85 | if self.dataset_name=='imagenet': 86 | assert(self.split=='train' or self.split=='val') 87 | self.mean_pix = [0.485, 0.456, 0.406] 88 | self.std_pix = [0.229, 0.224, 0.225] 89 | 90 | if self.split!='train': 91 | transforms_list = [ 92 | transforms.Resize(256), 93 | transforms.CenterCrop(224), 94 | ] 95 | else: 96 | if self.random_sized_crop: 97 | transforms_list = [ 98 | transforms.RandomResizedCrop(224), 99 | transforms.RandomHorizontalFlip(), 100 | ] 101 | else: 102 | transforms_list = [ 103 | transforms.Resize(256), 104 | transforms.RandomCrop(224), 105 | transforms.RandomHorizontalFlip(), 106 | ] 107 | self.transform = transforms.Compose(transforms_list) 108 | 109 | split_data_dir = _IMAGENET_DATASET_DIR + '/' + self.split 110 | 111 | self.data = datasets.ImageFolder(split_data_dir, self.transform) 112 | elif self.dataset_name=='places205': 113 | self.mean_pix = [0.485, 0.456, 0.406] 114 | self.std_pix = [0.229, 0.224, 0.225] 115 | if self.split!='train': 116 | transforms_list = [ 117 | transforms.CenterCrop(224), 118 | ] 119 | else: 120 | if self.random_sized_crop: 121 | transforms_list = [ 122 | transforms.RandomSizedCrop(224), 123 | transforms.RandomHorizontalFlip(), 124 | ] 125 | else: 126 | transforms_list = [ 127 | transforms.RandomCrop(224), 128 | transforms.RandomHorizontalFlip(), 129 | ] 130 | self.transform = transforms.Compose(transforms_list) 131 | self.data = Places205(root=_PLACES205_DATASET_DIR, split=self.split, 132 | transform=self.transform) 133 | else: 134 | raise ValueError('Not recognized dataset {0}'.format(dname)) 135 | 136 | def __getitem__(self, index): 137 | img, label = self.data[index] 138 | return img, int(label) 139 | 140 | def __len__(self): 141 | return len(self.data) 142 | 143 | class Denormalize(object): 144 | def __init__(self, mean, std): 145 | self.mean = mean 146 | self.std = std 147 | 148 | def __call__(self, tensor): 149 | for t, m, s in zip(tensor, self.mean, self.std): 150 | t.mul_(s).add_(m) 151 | return tensor 152 | 153 | class DataLoader(object): 154 | def __init__(self, 155 | dataset, 156 | resample=False, fillcolor=0, 157 | batch_size=1, 158 | unsupervised=True, 159 | epoch_size=None, 160 | num_workers=0, 161 | shuffle=True): 162 | self.dataset = dataset 163 | self.shuffle = shuffle 164 | self.epoch_size = epoch_size if epoch_size is not None else len(dataset) 165 | self.batch_size = batch_size 166 | self.unsupervised = unsupervised 167 | self.num_workers = num_workers 168 | 169 | mean_pix = self.dataset.mean_pix 170 | std_pix = self.dataset.std_pix 171 | self.transform = transforms.Compose([ 172 | transforms.ToTensor(), 173 | transforms.Normalize(mean=mean_pix, std=std_pix) 174 | ]) 175 | 176 | self.matrix_transform = transforms.Compose([ 177 | transforms.Normalize((0.,0.,112.,0.,0.,112.,6.4e-5,6.4e-5),(0.75,0.75,118.,0.75,0.75,118.,7.75e-4, 7.75e-4)) 178 | ]) 179 | self.inv_transform = transforms.Compose([ 180 | Denormalize(mean_pix, std_pix), 181 | lambda x: x.numpy() * 255.0, 182 | lambda x: x.transpose(1,2,0).astype(np.uint8), 183 | ]) 184 | #projective transformation 185 | 186 | self.resample = resample 187 | self.fillcolor = fillcolor 188 | 189 | with h5py.File('../homography.h5', 'r') as hf: 190 | self.homography = hf['homography'][:] 191 | 192 | def get_iterator(self, epoch=0): 193 | rand_seed = epoch * self.epoch_size 194 | random.seed(rand_seed) 195 | if self.unsupervised: 196 | def _load_function(idx): 197 | idx = idx % len(self.dataset) 198 | img0, _ = self.dataset[idx] 199 | width, height = img0.size 200 | center = (img0.size[0] * 0.5 + 0.5, img0.size[1] * 0.5 + 0.5) 201 | 202 | coeffs = self.homography[random.randint(0,499999)] 203 | 204 | kwargs = {"fillcolor": self.fillcolor} if PILLOW_VERSION[0] == '5' else {} 205 | img1 = img0.transform((width, height), Image.PERSPECTIVE, coeffs, self.resample, **kwargs) 206 | 207 | ori_img = self.transform(img0) 208 | warped_img = self.transform(img1) 209 | 210 | coeffs = torch.from_numpy(np.array(coeffs, np.float32, copy=False)).view(8, 1, 1) 211 | coeffs = self.matrix_transform(coeffs) 212 | coeffs = coeffs.view(8) 213 | 214 | return ori_img, warped_img, coeffs 215 | def _collate_fun(batch): 216 | batch = default_collate(batch) 217 | assert(len(batch)==3) 218 | return batch 219 | else: # supervised mode 220 | # if in supervised mode define a loader function that given the 221 | # index of an image it returns the image and its categorical label 222 | def _load_function(idx): 223 | idx = idx % len(self.dataset) 224 | img, categorical_label = self.dataset[idx] 225 | img = self.transform(img) 226 | return img, categorical_label 227 | _collate_fun = default_collate 228 | 229 | tnt_dataset = tnt.dataset.ListDataset(elem_list=range(self.epoch_size), 230 | load=_load_function) 231 | data_loader = tnt_dataset.parallel(batch_size=self.batch_size, 232 | collate_fn=_collate_fun, num_workers=self.num_workers, 233 | shuffle=self.shuffle) 234 | return data_loader 235 | 236 | def __call__(self, epoch=0): 237 | return self.get_iterator(epoch) 238 | 239 | def __len__(self): 240 | return self.epoch_size / self.batch_size 241 | 242 | if __name__ == '__main__': 243 | dataset = GenericDataset('imagenet','train',random_sized_crop=False) 244 | dataloader = DataLoader(dataset, batch_size=8, unsupervised=True, shift=28, scale=[0.8,1.2], resample=Image.BILINEAR, fillcolor=(128,128,128)) 245 | 246 | ii=0 247 | for b in dataloader(): 248 | data, data_,label = b 249 | vutils.save_image(data, 250 | './original_image_{}.png'.format(str(ii)), 251 | normalize=True) 252 | vutils.save_image(data_, 253 | './warped_image_{}.png'.format(str(ii)), 254 | normalize=True) 255 | print(ii) 256 | ii += 1 257 | break -------------------------------------------------------------------------------- /ImageNet/main.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import argparse 3 | import os 4 | import imp 5 | import algorithms as alg 6 | from dataloader import DataLoader, GenericDataset 7 | import PIL 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument('--exp', type=str, required=True, default='', help='config file with parameters of the experiment') 11 | parser.add_argument('--evaluate', default=False, action='store_true') 12 | parser.add_argument('--checkpoint', type=int, default=0, help='checkpoint (epoch id) that will be loaded') 13 | parser.add_argument('--num_workers', type=int, default=32, help='number of data loading workers') 14 | parser.add_argument('--cuda' , type=bool, default=True, help='enables cuda') 15 | parser.add_argument('--disp_step', type=int, default=50, help='display step during training') 16 | 17 | args_opt = parser.parse_args() 18 | 19 | exp_config_file = os.path.join('.','config',args_opt.exp+'.py') 20 | exp_directory = os.path.join('.','experiments',args_opt.exp) 21 | 22 | # Load the configuration params of the experiment 23 | print('Launching experiment: %s' % exp_config_file) 24 | config = imp.load_source("",exp_config_file).config 25 | config['exp_dir'] = exp_directory # the place where logs, models, and other stuff will be stored 26 | print("Loading experiment %s from file: %s" % (args_opt.exp, exp_config_file)) 27 | print("Generated logs, snapshots, and model files will be stored on %s" % (config['exp_dir'])) 28 | 29 | # Set train and test datasets and the corresponding data loaders 30 | data_train_opt = config['data_train_opt'] 31 | data_test_opt = config['data_test_opt'] 32 | num_imgs_per_cat = data_train_opt['num_imgs_per_cat'] if ('num_imgs_per_cat' in data_train_opt) else None 33 | 34 | dataset_train = GenericDataset( 35 | dataset_name=data_train_opt['dataset_name'], 36 | split=data_train_opt['split'], 37 | random_sized_crop=data_train_opt['random_sized_crop']) 38 | dataset_test = GenericDataset( 39 | dataset_name=data_test_opt['dataset_name'], 40 | split=data_test_opt['split'], 41 | random_sized_crop=data_test_opt['random_sized_crop']) 42 | 43 | dloader_train = DataLoader( 44 | dataset=dataset_train, 45 | batch_size=data_train_opt['batch_size'], 46 | unsupervised=data_train_opt['unsupervised'], 47 | epoch_size=data_train_opt['epoch_size'], 48 | num_workers=args_opt.num_workers, 49 | fillcolor=(128,128,128), 50 | resample=PIL.Image.BILINEAR, 51 | shuffle=True) 52 | 53 | dloader_test = DataLoader( 54 | dataset=dataset_test, 55 | batch_size=data_test_opt['batch_size'], 56 | unsupervised=data_test_opt['unsupervised'], 57 | epoch_size=data_test_opt['epoch_size'], 58 | num_workers=args_opt.num_workers, 59 | fillcolor=(128,128,128), 60 | resample=PIL.Image.BILINEAR, 61 | shuffle=False) 62 | 63 | config['disp_step'] = args_opt.disp_step 64 | algorithm = getattr(alg, config['algorithm_type'])(config) 65 | if args_opt.cuda: # enable cuda 66 | algorithm.load_to_gpu() 67 | if args_opt.checkpoint > 0: # load checkpoint 68 | algorithm.load_checkpoint(args_opt.checkpoint, train= (not args_opt.evaluate)) 69 | 70 | if not args_opt.evaluate: # train the algorithm 71 | algorithm.solve(dloader_train, dloader_test) 72 | else: 73 | algorithm.evaluate(dloader_test) # evaluate the algorithm 74 | -------------------------------------------------------------------------------- /ImageNet/save_homography.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import sys 3 | from PIL import Image 4 | import random 5 | import h5py 6 | 7 | def find_coeffs(pa, pb): 8 | matrix = [] 9 | for p1, p2 in zip(pa, pb): 10 | matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]]) 11 | matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]]) 12 | 13 | A = numpy.matrix(matrix, dtype=numpy.float) 14 | B = numpy.array(pb).reshape(8) 15 | 16 | res = numpy.dot(numpy.linalg.inv(A.T * A) * A.T, B) 17 | return numpy.array(res).reshape(8) 18 | 19 | all_coeffs = [] 20 | for kk in range(500000): 21 | width, height = (224, 224) 22 | center = (224 * 0.5 + 0.5, 224 * 0.5 + 0.5) 23 | 24 | shift = [float(random.randint(-28, 28)) for ii in range(8)] 25 | scale = random.uniform(0.8,1.2) 26 | 27 | pts = [((0-center[0])*scale+center[0], (0-center[1])*scale+center[1]), 28 | ((width-center[0])*scale+center[0], (0-center[1])*scale+center[1]), 29 | ((width-center[0])*scale+center[0], (height-center[1])*scale+center[1]), 30 | ((0-center[0])*scale+center[0], (height-center[1])*scale+center[1])] 31 | 32 | rotation = random.randint(0,3) 33 | pts = [pts[(ii+rotation)%4] for ii in range(4)] 34 | pts = [(pts[ii][0]+shift[2*ii], pts[ii][1]+shift[2*ii+1]) for ii in range(4)] 35 | 36 | coeffs = find_coeffs( 37 | pts, 38 | [(0, 0), (width, 0), (width, height), (0, height)] 39 | ) 40 | all_coeffs += [coeffs] 41 | 42 | all_coeffs = numpy.asarray(all_coeffs, dtype=numpy.float) 43 | mean = numpy.mean(all_coeffs, axis=0) 44 | std = numpy.std(all_coeffs, axis=0) 45 | print(mean) 46 | print(std) 47 | with h5py.File('../homography.h5', 'w') as hf: 48 | hf.create_dataset('homography', data=all_coeffs) 49 | -------------------------------------------------------------------------------- /ImageNet/utils.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 | import imp 8 | from tqdm import tqdm 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.parallel 12 | import torch.optim 13 | import torchnet as tnt 14 | 15 | 16 | import numbers 17 | 18 | class FastConfusionMeter(object): 19 | def __init__(self, k, normalized = False): 20 | #super(FastConfusionMeter, self).__init__() 21 | self.conf = np.ndarray((k,k), dtype=np.int32) 22 | self.normalized = normalized 23 | self.reset() 24 | 25 | def reset(self): 26 | self.conf.fill(0) 27 | 28 | def add(self, output, target): 29 | output = output.cpu().squeeze().numpy() 30 | target = target.cpu().squeeze().numpy() 31 | 32 | if np.ndim(output) == 1: 33 | output = output[None] 34 | 35 | onehot = np.ndim(target) != 1 36 | assert output.shape[0] == target.shape[0], \ 37 | 'number of targets and outputs do not match' 38 | assert output.shape[1] == self.conf.shape[0], \ 39 | 'number of outputs does not match size of confusion matrix' 40 | assert not onehot or target.shape[1] == output.shape[1], \ 41 | 'target should be 1D Tensor or have size of output (one-hot)' 42 | if onehot: 43 | assert (target >= 0).all() and (target <= 1).all(), \ 44 | 'in one-hot encoding, target values should be 0 or 1' 45 | assert (target.sum(1) == 1).all(), \ 46 | 'multi-label setting is not supported' 47 | 48 | target = target.argmax(1) if onehot else target 49 | pred = output.argmax(1) 50 | 51 | target = target.astype(np.int32) 52 | pred = pred.astype(np.int32) 53 | conf_this = np.bincount(target * self.conf.shape[0] + pred,minlength=np.prod(self.conf.shape)) 54 | conf_this = conf_this.astype(self.conf.dtype).reshape(self.conf.shape) 55 | self.conf += conf_this 56 | 57 | def value(self): 58 | if self.normalized: 59 | conf = self.conf.astype(np.float32) 60 | return conf / conf.sum(1).clip(min=1e-12)[:,None] 61 | else: 62 | return self.conf 63 | 64 | def getConfMatrixResults(matrix): 65 | assert(len(matrix.shape)==2 and matrix.shape[0]==matrix.shape[1]) 66 | 67 | count_correct = np.diag(matrix) 68 | count_preds = matrix.sum(1) 69 | count_gts = matrix.sum(0) 70 | epsilon = np.finfo(np.float32).eps 71 | accuracies = count_correct / (count_gts + epsilon) 72 | IoUs = count_correct / (count_gts + count_preds - count_correct + epsilon) 73 | totAccuracy = count_correct.sum() / (matrix.sum() + epsilon) 74 | 75 | num_valid = (count_gts > 0).sum() 76 | meanAccuracy = accuracies.sum() / (num_valid + epsilon) 77 | meanIoU = IoUs.sum() / (num_valid + epsilon) 78 | 79 | result = {'totAccuracy': round(totAccuracy,4), 'meanAccuracy': round(meanAccuracy,4), 'meanIoU': round(meanIoU,4)} 80 | if num_valid == 2: 81 | result['IoUs_bg'] = round(IoUs[0],4) 82 | result['IoUs_fg'] = round(IoUs[1],4) 83 | 84 | return result 85 | 86 | class AverageConfMeter(object): 87 | def __init__(self): 88 | self.reset() 89 | 90 | def reset(self): 91 | self.val = np.asarray(0, dtype=np.float64) 92 | self.avg = np.asarray(0, dtype=np.float64) 93 | self.sum = np.asarray(0, dtype=np.float64) 94 | self.count = 0 95 | 96 | def update(self, val): 97 | self.val = val 98 | if self.count == 0: 99 | self.sum = val.copy().astype(np.float64) 100 | else: 101 | self.sum += val.astype(np.float64) 102 | 103 | self.count += 1 104 | self.avg = getConfMatrixResults(self.sum) 105 | 106 | class AverageMeter(object): 107 | """Computes and stores the average and current value""" 108 | def __init__(self): 109 | self.reset() 110 | 111 | def reset(self): 112 | self.val = 0 113 | self.avg = 0.0 114 | self.sum = 0.0 115 | self.count = 0 116 | 117 | def update(self, val, n=1): 118 | self.val = val 119 | self.sum += float(val * n) 120 | self.count += n 121 | self.avg = round(self.sum / self.count,4) 122 | 123 | class LAverageMeter(object): 124 | """Computes and stores the average and current value""" 125 | def __init__(self): 126 | self.reset() 127 | 128 | def reset(self): 129 | self.val = [] 130 | self.avg = [] 131 | self.sum = [] 132 | self.count = 0 133 | 134 | def update(self, val): 135 | self.val = val 136 | self.count += 1 137 | if len(self.sum) == 0: 138 | assert(self.count == 1) 139 | self.sum = [v for v in val] 140 | self.avg = [round(v,4) for v in val] 141 | else: 142 | assert(len(self.sum) == len(val)) 143 | for i, v in enumerate(val): 144 | self.sum[i] += v 145 | self.avg[i] = round(self.sum[i] / self.count,4) 146 | 147 | class DAverageMeter(object): 148 | def __init__(self): 149 | self.reset() 150 | 151 | def reset(self): 152 | self.values = {} 153 | 154 | def update(self, values): 155 | assert(isinstance(values, dict)) 156 | for key, val in values.items(): 157 | if isinstance(val, (float, int)): 158 | if not (key in self.values): 159 | self.values[key] = AverageMeter() 160 | self.values[key].update(val) 161 | elif isinstance(val, (tnt.meter.ConfusionMeter,FastConfusionMeter)): 162 | if not (key in self.values): 163 | self.values[key] = AverageConfMeter() 164 | self.values[key].update(val.value()) 165 | elif isinstance(val, AverageConfMeter): 166 | if not (key in self.values): 167 | self.values[key] = AverageConfMeter() 168 | self.values[key].update(val.sum) 169 | elif isinstance(val, dict): 170 | if not (key in self.values): 171 | self.values[key] = DAverageMeter() 172 | self.values[key].update(val) 173 | elif isinstance(val, list): 174 | if not (key in self.values): 175 | self.values[key] = LAverageMeter() 176 | self.values[key].update(val) 177 | 178 | def average(self): 179 | average = {} 180 | for key, val in self.values.items(): 181 | if isinstance(val, type(self)): 182 | average[key] = val.average() 183 | else: 184 | average[key] = val.avg 185 | 186 | return average 187 | 188 | def __str__(self): 189 | ave_stats = self.average() 190 | return ave_stats.__str__() 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AVT: Unsupervised Learning of Transformation Equivariant Representations by Autoencoding Variational Transformations 2 | The project website for "Autoencoding Variational Transformations" 3 | 4 | ## Abstract 5 | The learning of Transformation-Equivariant Representations (TERs), which is introduced by Hinton et al., 6 | has been considered as a principle to reveal visual structures under various transformations. It contains the celebrated Convolutional Neural Networks (CNNs) as a special case that only equivary to the translations. In contrast, we seek to train TERs for a generic class of transformations and train them in an unsupervised fashion. To this end, we present a novel principled method by Autoencoding Variational Transformations (AVT), compared with the conventional approach to autoencoding data. Formally, given transformed images, the AVT seeks to train the networks by maximizing the mutual information between the transformations and representations. This ensures the resultant TERs of individual images contain the intrinsic information about their visual structures that would equivary extricably under various transformations in a generalized nonlinear case. Technically, we show that the resultant optimization problem can be efficiently solved by maximizing a variational lower-bound of the mutual information. This variational approach introduces a transformation decoder to approximate the intractable posterior of transformations, resulting in an autoencoding architecture with a pair of the representation encoder and the transformation decoder. Experiments demonstrate the proposed AVT model sets a new record for the performances on unsupervised tasks, greatly closing the performance gap to the supervised models. 7 | 8 | ## Formulation 9 | 10 | | ![AVT](https://github.com/maple-research-lab/AVT-pytorch/blob/master/resources/AVT.PNG) | 11 | |:--:| 12 | | *Figure 1. The architecture of the proposed AVT. The original and transformed images are fed through the encoder pθ where 1 denotes an identity transformation to generate the representation of the original image. The resultant representations ˜z and z of original and transformed images are sampled and fed into the transformation decoder qφ from which the transformation t is sampled.* | 13 | 14 | As illustrated in Figure 1, we implement the transformation decoder by using a Siamese encoder network 15 | with shared weights to represent the original and transformed images with ˜z and z respectively, where the mean and the variance the sampled transformation are predicted from the concatenation of both representations. 16 | 17 | For details, please refer to [our paper](https://arxiv.org/pdf/1903.10863.pdf). 18 | 19 | ## Run our codes 20 | ### Requirements 21 | - Python == 2.7 22 | - pytorch == 1.0.1 23 | - torchvision == 0.2.1 24 | - PIL == 5.4.1 25 | ### Note 26 | Please use the torchvision with version 0.2.1. The code does not support the newest version of torchvision. 27 | ### Cifar10 28 | cd cifar 29 | Unsupervised learning: 30 | 31 | CUDA_VISIBLE_DEVICES=0 python main.py --cuda --outf ./output --dataroot $YOUR_CIFAR10_PATH$ 32 | Supervised evaluation with two FC layers: 33 | 34 | python classification.py --dataroot $YOUR_CIFAR10_PATH$ --epochs 200 --schedule 100 150 --gamma 0.1 -c ./output_cls --net ./output/net_epoch_4499.pth --gpu-id 0 35 | ### ImageNet 36 | cd ImageNet 37 | Generate and save 0.5 million projective transformation parameters: 38 | 39 | python save_homography.py 40 | Unsupervised learning: 41 | 42 | CUDA_VISIBLE_DEVICES=0 python main.py --exp ImageNet_Unsupervised 43 | Supervised evaluation with non-linear classifiers: 44 | 45 | CUDA_VISIBLE_DEVICES=0 python main.py --exp ImageNet_NonLinearClassifiers 46 | Supervised evaluation with linear classifiers (max pooling): 47 | 48 | CUDA_VISIBLE_DEVICES=0 python main.py --exp ImageNet_LinearClassifiers_Maxpooling 49 | Supervised evaluation with linear classifiers (average pooling): 50 | 51 | CUDA_VISIBLE_DEVICES=0 python main.py --exp ImageNet_LinearClassifiers_Avgpooling 52 | 53 | To use the pretrained ImageNet model: 54 | 55 | mkdir experiments 56 | cd experiments 57 | mkdir ImageNet_Unsupervised 58 | 59 | Please download the pre-trained model from the link: https://1drv.ms/u/s!AhnMU9glhsl-x0SBW-EI709dM5pc?e=KZyQg0 and put the models under ./experiments/ImageNet_Unsupervised 60 | 61 | ### Places205 62 | Firstly pretrain the model on Imagenet, then evalutate the model with linear classifiers (max pooling): 63 | 64 | CUDA_VISIBLE_DEVICES=0 python main.py --exp Places205_LinearClassifiers_Maxpooling 65 | 66 | Supervised evalutation with linear classifiers (average pooling): 67 | 68 | CUDA_VISIBLE_DEVICES=0 python main.py --exp Places205_LinearClassifiers_Avgpooling 69 | 70 | ## Citation 71 | 72 | Guo-Jun Qi, Liheng Zhang, Chang Wen Chen, Qi Tian. AVT: Unsupervised Learning of Transformation Equivariant Representations by Autoencoding Variational Transformations, in Proceedings of IEEE International Conference on Computer Vision (ICCV), 2019. [[pdf](https://arxiv.org/pdf/1903.10863.pdf)] 73 | 74 | ## Disclaimer 75 | 76 | Some of our codes reuse the github project [FeatureLearningRotNet](https://github.com/gidariss/FeatureLearningRotNet). 77 | 78 | ## License 79 | 80 | This code is released under the MIT License. 81 | -------------------------------------------------------------------------------- /cifar/NetworkInNetwork.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | 6 | class BasicBlock(nn.Module): 7 | def __init__(self, in_planes, out_planes, kernel_size): 8 | super(BasicBlock, self).__init__() 9 | padding = (kernel_size-1)/2 10 | self.layers = nn.Sequential() 11 | self.layers.add_module('Conv', nn.Conv2d(in_planes, out_planes, \ 12 | kernel_size=kernel_size, stride=1, padding=padding, bias=False)) 13 | self.layers.add_module('BatchNorm', nn.BatchNorm2d(out_planes)) 14 | self.layers.add_module('ReLU', nn.ReLU(inplace=True)) 15 | 16 | def forward(self, x): 17 | return self.layers(x) 18 | 19 | feat = F.avg_pool2d(feat, feat.size(3)).view(-1, self.nChannels) 20 | 21 | class EncBlock(nn.Module): 22 | def __init__(self, in_planes, out_planes, kernel_size): 23 | super(EncBlock, self).__init__() 24 | padding = (kernel_size-1)/2 25 | self.layers = nn.Sequential() 26 | self.layers.add_module('Conv', nn.Conv2d(in_planes, out_planes, \ 27 | kernel_size=kernel_size, stride=1, padding=padding, bias=False)) 28 | self.layers.add_module('BatchNorm', nn.BatchNorm2d(out_planes)) 29 | 30 | def forward(self, x): 31 | out = self.layers(x) 32 | return torch.cat([x,out], dim=1) 33 | 34 | 35 | class GlobalAveragePooling(nn.Module): 36 | def __init__(self): 37 | super(GlobalAveragePooling, self).__init__() 38 | 39 | def forward(self, feat): 40 | num_channels = feat.size(1) 41 | return F.avg_pool2d(feat, (feat.size(2), feat.size(3))).view(-1, num_channels) 42 | 43 | class NetworkInNetwork(nn.Module): 44 | def __init__(self, _num_inchannels=3, _num_stages=3, _use_avg_on_conv3=True): 45 | super(NetworkInNetwork, self).__init__() 46 | 47 | num_inchannels = _num_inchannels 48 | num_stages = _num_stages 49 | use_avg_on_conv3 = _use_avg_on_conv3 50 | 51 | assert(num_stages >= 3) 52 | nChannels = 192 53 | nChannels2 = 160 54 | nChannels3 = 96 55 | 56 | blocks = [nn.Sequential() for i in range(num_stages)] 57 | # 1st block 58 | blocks[0].add_module('Block1_ConvB1', BasicBlock(num_inchannels, nChannels, 5)) 59 | blocks[0].add_module('Block1_ConvB2', BasicBlock(nChannels, nChannels2, 1)) 60 | blocks[0].add_module('Block1_ConvB3', BasicBlock(nChannels2, nChannels3, 1)) 61 | blocks[0].add_module('Block1_MaxPool', nn.MaxPool2d(kernel_size=3,stride=2,padding=1)) 62 | 63 | # 2nd block 64 | blocks[1].add_module('Block2_ConvB1', BasicBlock(nChannels3, nChannels, 5)) 65 | blocks[1].add_module('Block2_ConvB2', BasicBlock(nChannels, nChannels, 1)) 66 | blocks[1].add_module('Block2_ConvB3', BasicBlock(nChannels, nChannels, 1)) 67 | blocks[1].add_module('Block2_AvgPool', nn.AvgPool2d(kernel_size=3,stride=2,padding=1)) 68 | blocks[1].add_module('Block2_Encode', EncBlock(nChannels, nChannels, 1)) 69 | 70 | # 3rd block 71 | blocks[2].add_module('Block3_ConvB1', BasicBlock(nChannels, nChannels, 3)) 72 | blocks[2].add_module('Block3_ConvB2', BasicBlock(nChannels, nChannels, 1)) 73 | blocks[2].add_module('Block3_ConvB3', BasicBlock(nChannels, nChannels, 1)) 74 | 75 | if num_stages > 3 and use_avg_on_conv3: 76 | blocks[2].add_module('Block3_AvgPool', nn.AvgPool2d(kernel_size=3,stride=2,padding=1)) 77 | for s in range(3, num_stages): 78 | blocks[s].add_module('Block'+str(s+1)+'_ConvB1', BasicBlock(nChannels, nChannels, 3)) 79 | blocks[s].add_module('Block'+str(s+1)+'_ConvB2', BasicBlock(nChannels, nChannels, 1)) 80 | blocks[s].add_module('Block'+str(s+1)+'_ConvB3', BasicBlock(nChannels, nChannels, 1)) 81 | 82 | # global average pooling and classifier 83 | blocks.append(nn.Sequential()) 84 | blocks[-1].add_module('GlobalAveragePooling', GlobalAveragePooling()) 85 | 86 | self._feature_blocks = nn.ModuleList(blocks) 87 | self.all_feat_names = ['conv'+str(s+1) for s in range(num_stages)] + ['classifier',] 88 | assert(len(self.all_feat_names) == len(self._feature_blocks)) 89 | 90 | self.weight_initialization() 91 | 92 | def _parse_out_keys_arg(self, out_feat_keys): 93 | 94 | # By default return the features of the last layer / module. 95 | out_feat_keys = [self.all_feat_names[-1],] if out_feat_keys is None else out_feat_keys 96 | 97 | if len(out_feat_keys) == 0: 98 | raise ValueError('Empty list of output feature keys.') 99 | for f, key in enumerate(out_feat_keys): 100 | if key not in self.all_feat_names: 101 | raise ValueError('Feature with name {0} does not exist. Existing features: {1}.'.format(key, self.all_feat_names)) 102 | elif key in out_feat_keys[:f]: 103 | raise ValueError('Duplicate output feature key: {0}.'.format(key)) 104 | 105 | # Find the highest output feature in `out_feat_keys 106 | max_out_feat = max([self.all_feat_names.index(key) for key in out_feat_keys]) 107 | 108 | return out_feat_keys, max_out_feat 109 | 110 | def forward(self, x, out_feat_keys=None): 111 | """Forward an image `x` through the network and return the asked output features. 112 | 113 | Args: 114 | x: input image. 115 | out_feat_keys: a list/tuple with the feature names of the features 116 | that the function should return. By default the last feature of 117 | the network is returned. 118 | 119 | Return: 120 | out_feats: If multiple output features were asked then `out_feats` 121 | is a list with the asked output features placed in the same 122 | order as in `out_feat_keys`. If a single output feature was 123 | asked then `out_feats` is that output feature (and not a list). 124 | """ 125 | out_feat_keys, max_out_feat = self._parse_out_keys_arg(out_feat_keys) 126 | out_feats = [None] * len(out_feat_keys) 127 | 128 | feat = x 129 | #encode 130 | for f in range(2): 131 | feat = self._feature_blocks[f](feat) 132 | key = self.all_feat_names[f] 133 | if key in out_feat_keys: 134 | out_feats[out_feat_keys.index(key)] = feat 135 | 136 | #reparameterize 137 | mu = feat[:,:192] 138 | logvar = feat[:, 192:] 139 | std = torch.exp(0.5*logvar) 140 | eps = torch.randn_like(std) 141 | feat = eps.mul(std * 0.001).add_(mu) 142 | 143 | #decode 144 | for f in range(2, max_out_feat+1): 145 | feat = self._feature_blocks[f](feat) 146 | key = self.all_feat_names[f] 147 | if key in out_feat_keys: 148 | out_feats[out_feat_keys.index(key)] = feat 149 | 150 | out_feats = out_feats[0] if len(out_feats)==1 else out_feats 151 | return out_feats 152 | 153 | 154 | def weight_initialization(self): 155 | for m in self.modules(): 156 | if isinstance(m, nn.Conv2d): 157 | if m.weight.requires_grad: 158 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 159 | m.weight.data.normal_(0, math.sqrt(2. / n)) 160 | elif isinstance(m, nn.BatchNorm2d): 161 | if m.weight.requires_grad: 162 | m.weight.data.fill_(1) 163 | if m.bias.requires_grad: 164 | m.bias.data.zero_() 165 | elif isinstance(m, nn.Linear): 166 | if m.bias.requires_grad: 167 | m.bias.data.zero_() 168 | 169 | class Regressor(nn.Module): 170 | def __init__(self, _num_stages=3, _use_avg_on_conv3=True, indim=384, num_classes=8): 171 | super(Regressor, self).__init__() 172 | self.nin = NetworkInNetwork(_num_stages=_num_stages, _use_avg_on_conv3=_use_avg_on_conv3) 173 | self.fc = nn.Linear(indim, num_classes) 174 | self.fc2 = nn.Linear(indim, num_classes) 175 | for m in self.modules(): 176 | if isinstance(m, nn.Linear): 177 | m.bias.data.zero_() 178 | 179 | def forward(self, x1, x2, out_feat_keys=None): 180 | x1 = self.nin(x1, out_feat_keys) 181 | x2 = self.nin(x2, out_feat_keys) 182 | if out_feat_keys==None: 183 | x = torch.cat((x1,x2), dim=1) 184 | return x1, x2, self.fc(x), self.fc2(x) 185 | else: 186 | return x1, x2 187 | 188 | -------------------------------------------------------------------------------- /cifar/NonLinearClassifier.py: -------------------------------------------------------------------------------- 1 | import math 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | import numpy as np 6 | 7 | class BasicBlock(nn.Module): 8 | def __init__(self, in_planes, out_planes, kernel_size, stride=1): 9 | super(BasicBlock, self).__init__() 10 | padding = (kernel_size-1)/2 11 | self.layers = nn.Sequential() 12 | self.layers.add_module('Conv', nn.Conv2d(in_planes, out_planes, \ 13 | kernel_size=kernel_size, stride=stride, padding=padding, bias=False)) 14 | self.layers.add_module('BatchNorm', nn.BatchNorm2d(out_planes)) 15 | self.layers.add_module('ReLU', nn.ReLU(inplace=True)) 16 | 17 | def forward(self, x): 18 | return self.layers(x) 19 | 20 | class GlobalAvgPool(nn.Module): 21 | def __init__(self): 22 | super(GlobalAvgPool, self).__init__() 23 | 24 | def forward(self, feat): 25 | assert(feat.size(2) == feat.size(3)) 26 | feat_avg = F.avg_pool2d(feat, feat.size(2)).view(-1, feat.size(1)) 27 | return feat_avg 28 | 29 | class Flatten(nn.Module): 30 | def __init__(self): 31 | super(Flatten, self).__init__() 32 | 33 | def forward(self, feat): 34 | return feat.view(feat.size(0), -1) 35 | 36 | class Classifier(nn.Module): 37 | def __init__(self, _nChannels, _num_classes, _cls_type): 38 | super(Classifier, self).__init__() 39 | nChannels = _nChannels 40 | num_classes = _num_classes 41 | self.cls_type = _cls_type 42 | 43 | self.classifier = nn.Sequential() 44 | 45 | if self.cls_type == 'MultLayer': 46 | nFeats = min(num_classes*20, 2048) 47 | self.classifier.add_module('Flatten', Flatten()) 48 | self.classifier.add_module('Liniear_1', nn.Linear(nChannels, nFeats, bias=False)) 49 | self.classifier.add_module('BatchNorm_1', nn.BatchNorm1d(nFeats)) 50 | self.classifier.add_module('ReLU_1', nn.ReLU(inplace=True)) 51 | self.classifier.add_module('Liniear_2', nn.Linear(nFeats, nFeats, bias=False)) 52 | self.classifier.add_module('BatchNorm2d', nn.BatchNorm1d(nFeats)) 53 | self.classifier.add_module('ReLU_2', nn.ReLU(inplace=True)) 54 | self.classifier.add_module('Liniear_F', nn.Linear(nFeats, num_classes)) 55 | 56 | elif self.cls_type == 'MultLayerFC1': 57 | self.classifier.add_module('Batchnorm', nn.BatchNorm2d(nChannels/8/8, affine=False)) 58 | self.classifier.add_module('Flatten', Flatten()) 59 | self.classifier.add_module('Liniear_F', nn.Linear(nChannels, num_classes)) 60 | elif self.cls_type == 'MultLayerFC2': 61 | nFeats = min(num_classes*20, 2048) 62 | self.classifier.add_module('Flatten', Flatten()) 63 | self.classifier.add_module('Liniear_1', nn.Linear(nChannels, nFeats, bias=False)) 64 | self.classifier.add_module('BatchNorm_1', nn.BatchNorm1d(nFeats)) 65 | self.classifier.add_module('ReLU_1', nn.ReLU(inplace=True)) 66 | self.classifier.add_module('Liniear_F', nn.Linear(nFeats, num_classes)) 67 | 68 | elif self.cls_type == 'NIN_ConvBlock3': 69 | self.classifier.add_module('Block3_ConvB1', BasicBlock(nChannels, 192, 3)) 70 | self.classifier.add_module('Block3_ConvB2', BasicBlock(192, 192, 1)) 71 | self.classifier.add_module('Block3_ConvB3', BasicBlock(192, 192, 1)) 72 | self.classifier.add_module('GlobalAvgPool', GlobalAvgPool()) 73 | self.classifier.add_module('Liniear_F', nn.Linear(192, num_classes)) 74 | elif self.cls_type == 'Alexnet_conv5' or self.cls_type == 'Alexnet_conv4': 75 | if self.cls_type == 'Alexnet_conv4': 76 | block5 = nn.Sequential( 77 | nn.Conv2d(256, 256, kernel_size=3, padding=1), 78 | nn.BatchNorm2d(256), 79 | nn.ReLU(inplace=True), 80 | ) 81 | self.classifier.add_module('ConvB5', block5) 82 | self.classifier.add_module('Pool5', nn.MaxPool2d(kernel_size=3, stride=2)) 83 | self.classifier.add_module('Flatten', Flatten()) 84 | self.classifier.add_module('Linear1', nn.Linear(256*6*6, 4096, bias=False)) 85 | self.classifier.add_module('BatchNorm1', nn.BatchNorm1d(4096)) 86 | self.classifier.add_module('ReLU1', nn.ReLU(inplace=True)) 87 | self.classifier.add_module('Liniear2', nn.Linear(4096, 4096, bias=False)) 88 | self.classifier.add_module('BatchNorm2', nn.BatchNorm1d(4096)) 89 | self.classifier.add_module('ReLU2', nn.ReLU(inplace=True)) 90 | self.classifier.add_module('LinearF', nn.Linear(4096, num_classes)) 91 | else: 92 | raise ValueError('Not recognized classifier type: %s' % self.cls_type) 93 | 94 | self.initilize() 95 | 96 | def forward(self, feat): 97 | return self.classifier(feat) 98 | 99 | def initilize(self): 100 | for m in self.modules(): 101 | if isinstance(m, nn.Conv2d): 102 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 103 | m.weight.data.normal_(0, math.sqrt(2. / n)) 104 | elif isinstance(m, nn.BatchNorm1d): 105 | m.weight.data.fill_(1) 106 | m.bias.data.zero_() 107 | elif isinstance(m, nn.BatchNorm2d): 108 | if m.weight is not None: 109 | m.weight.data.fill_(1) 110 | if m.bias is not None: 111 | m.bias.data.zero_() 112 | elif isinstance(m, nn.Linear): 113 | fin = m.in_features 114 | fout = m.out_features 115 | std_val = np.sqrt(2.0/fout) 116 | m.weight.data.normal_(0.0, std_val) 117 | if m.bias is not None: 118 | m.bias.data.fill_(0.0) 119 | -------------------------------------------------------------------------------- /cifar/classification.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Training script for CIFAR-10/100 3 | Copyright (c) Wei YANG, 2017 4 | ''' 5 | from __future__ import print_function 6 | 7 | import argparse 8 | import os 9 | import shutil 10 | import time 11 | import random 12 | 13 | import torch 14 | import torch.nn as nn 15 | import torch.nn.parallel 16 | import torch.backends.cudnn as cudnn 17 | import torch.optim as optim 18 | import torch.utils.data as data 19 | import torchvision.transforms as transforms 20 | import torchvision.datasets as datasets 21 | 22 | from NetworkInNetwork import Regressor 23 | from NonLinearClassifier import Classifier 24 | 25 | from utils import Bar, Logger, AverageMeter, accuracy, mkdir_p, savefig 26 | 27 | parser = argparse.ArgumentParser(description='PyTorch CIFAR10/100 Training') 28 | # Datasets 29 | parser.add_argument('--dataroot', default='/home/liheng/cifar10', help='path to dataset') 30 | parser.add_argument('-j', '--workers', default=2, type=int, metavar='N', 31 | help='number of data loading workers (default: 4)') 32 | # Optimization options 33 | parser.add_argument('--epochs', default=200, type=int, metavar='N', 34 | help='number of total epochs to run') 35 | parser.add_argument('--start-epoch', default=0, type=int, metavar='N', 36 | help='manual epoch number (useful on restarts)') 37 | parser.add_argument('--train-batch', default=128, type=int, metavar='N', 38 | help='train batchsize') 39 | parser.add_argument('--test-batch', default=100, type=int, metavar='N', 40 | help='test batchsize') 41 | parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, 42 | metavar='LR', help='initial learning rate') 43 | parser.add_argument('--schedule', type=int, nargs='+', default=[100, 150], 44 | help='Decrease learning rate at these epochs.') 45 | parser.add_argument('--gamma', type=float, default=0.1, help='LR is multiplied by gamma on schedule.') 46 | parser.add_argument('--momentum', default=0.9, type=float, metavar='M', 47 | help='momentum') 48 | parser.add_argument('--weight-decay', '--wd', default=5e-4, type=float, 49 | metavar='W', help='weight decay (default: 1e-4)') 50 | # Checkpoints 51 | parser.add_argument('-c', '--checkpoint', default='checkpoint', type=str, metavar='PATH', 52 | help='path to save checkpoint (default: checkpoint)') 53 | parser.add_argument('--resume', default='', type=str, metavar='PATH', 54 | help='path to latest checkpoint (default: none)') 55 | parser.add_argument('--net', default='', type=str, metavar='PATH', 56 | help='path to latest checkpoint (default: none)') 57 | # Miscs 58 | parser.add_argument('--manualSeed', type=int, help='manual seed') 59 | parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', 60 | help='evaluate model on validation set') 61 | #Device options 62 | parser.add_argument('--gpu-id', default='0', type=str, 63 | help='id(s) for CUDA_VISIBLE_DEVICES') 64 | 65 | args = parser.parse_args() 66 | state = {k: v for k, v in args._get_kwargs()} 67 | 68 | # Use CUDA 69 | os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu_id 70 | use_cuda = torch.cuda.is_available() 71 | device = torch.device("cuda:0" if use_cuda else "cpu") 72 | 73 | # Random seed 74 | if args.manualSeed is None: 75 | args.manualSeed = random.randint(1, 10000) 76 | random.seed(args.manualSeed) 77 | torch.manual_seed(args.manualSeed) 78 | if use_cuda: 79 | torch.cuda.manual_seed_all(args.manualSeed) 80 | 81 | best_acc = 0 # best test accuracy 82 | 83 | def main(): 84 | global best_acc 85 | global device 86 | start_epoch = args.start_epoch # start from epoch 0 or last checkpoint epoch 87 | 88 | if not os.path.isdir(args.checkpoint): 89 | mkdir_p(args.checkpoint) 90 | 91 | # Data 92 | print('==> Preparing dataset cifar10') 93 | transform_train = transforms.Compose([ 94 | transforms.RandomCrop(32, padding=4), 95 | transforms.RandomHorizontalFlip(), 96 | transforms.ToTensor(), 97 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 98 | ]) 99 | 100 | transform_test = transforms.Compose([ 101 | transforms.ToTensor(), 102 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 103 | ]) 104 | 105 | dataloader = datasets.CIFAR10 106 | num_classes = 10 107 | 108 | trainset = dataloader(root=args.dataroot, train=True, download=True, transform=transform_train) 109 | trainloader = data.DataLoader(trainset, batch_size=args.train_batch, shuffle=True, num_workers=args.workers) 110 | 111 | testset = dataloader(root=args.dataroot, train=False, download=False, transform=transform_test) 112 | testloader = data.DataLoader(testset, batch_size=args.test_batch, shuffle=False, num_workers=args.workers) 113 | 114 | # Model 115 | net = Regressor(_num_stages=4, _use_avg_on_conv3=False).to(device) 116 | net = torch.nn.DataParallel(net, device_ids=[0]) 117 | if args.net != '': 118 | net.load_state_dict(torch.load(args.net)) 119 | 120 | model = Classifier(_nChannels=192*8*8, _num_classes=10, _cls_type='MultLayerFC2').to(device) 121 | model = torch.nn.DataParallel(model, device_ids=[0]) 122 | 123 | cudnn.benchmark = True 124 | print(' Total params: %.2fM' % (sum(p.numel() for p in model.parameters())/1000000.0)) 125 | 126 | criterion = nn.CrossEntropyLoss() 127 | optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay, nesterov=True) 128 | 129 | # Resume 130 | title = 'cifar-10-' 131 | if args.resume: 132 | # Load checkpoint. 133 | print('==> Resuming from checkpoint..') 134 | assert os.path.isfile(args.resume), 'Error: no checkpoint directory found!' 135 | args.checkpoint = os.path.dirname(args.resume) 136 | checkpoint = torch.load(args.resume) 137 | best_acc = checkpoint['best_acc'] 138 | start_epoch = checkpoint['epoch'] 139 | model.load_state_dict(checkpoint['state_dict']) 140 | optimizer.load_state_dict(checkpoint['optimizer']) 141 | logger = Logger(os.path.join(args.checkpoint, 'log.txt'), title=title, resume=True) 142 | else: 143 | logger = Logger(os.path.join(args.checkpoint, 'log.txt'), title=title) 144 | logger.set_names(['Learning Rate', 'Train Loss', 'Valid Loss', 'Train Acc.', 'Valid Acc.']) 145 | 146 | 147 | if args.evaluate: 148 | print('\nEvaluation only') 149 | test_loss, test_acc = test(testloader, net, model, criterion, start_epoch, use_cuda, device) 150 | print(' Test Loss: %.8f, Test Acc: %.2f' % (test_loss, test_acc)) 151 | return 152 | 153 | # Train and val 154 | for epoch in range(start_epoch, args.epochs): 155 | adjust_learning_rate(optimizer, epoch) 156 | 157 | print('\nEpoch: [%d | %d] LR: %f' % (epoch + 1, args.epochs, state['lr'])) 158 | 159 | train_loss, train_acc = train(trainloader, net, model, criterion, optimizer, epoch, use_cuda, device) 160 | test_loss, test_acc = test(testloader, net, model, criterion, epoch, use_cuda, device) 161 | 162 | # append logger file 163 | logger.append([state['lr'], train_loss, test_loss, train_acc, test_acc]) 164 | 165 | # save model 166 | is_best = test_acc > best_acc 167 | best_acc = max(test_acc, best_acc) 168 | save_checkpoint({ 169 | 'epoch': epoch + 1, 170 | 'state_dict': model.state_dict(), 171 | 'acc': test_acc, 172 | 'best_acc': best_acc, 173 | 'optimizer' : optimizer.state_dict(), 174 | }, is_best, checkpoint=args.checkpoint) 175 | 176 | logger.close() 177 | logger.plot() 178 | savefig(os.path.join(args.checkpoint, 'log.eps')) 179 | 180 | print('Best acc:') 181 | print(best_acc) 182 | 183 | def train(trainloader, net, model, criterion, optimizer, epoch, use_cuda, device): 184 | # switch to train mode 185 | net.eval() 186 | model.train() 187 | 188 | batch_time = AverageMeter() 189 | data_time = AverageMeter() 190 | losses = AverageMeter() 191 | top1 = AverageMeter() 192 | top5 = AverageMeter() 193 | end = time.time() 194 | 195 | bar = Bar('Processing', max=len(trainloader)) 196 | for batch_idx, (inputs, targets) in enumerate(trainloader): 197 | # measure data loading time 198 | data_time.update(time.time() - end) 199 | 200 | if use_cuda: 201 | inputs, targets = inputs.to(device), targets.to(device) 202 | 203 | # compute output 204 | f1, f2 = net(inputs, inputs, out_feat_keys=['conv2']) 205 | 206 | out_mean = f1[:, :192] 207 | out_var = f1[:, 192:] 208 | std = torch.exp(0.5*out_var) 209 | 210 | feats = [] 211 | for _ in range(5): 212 | eps = torch.rand_like(std) 213 | feat = eps.mul(std * 0.001).add_(out_mean) 214 | feats.append(feat) 215 | 216 | feat = feats[0] 217 | for ii in range(1, 5): 218 | feat += feats[ii] 219 | 220 | feat = feat / 5. 221 | 222 | outputs = model(feat) 223 | loss = criterion(outputs, targets) 224 | 225 | # measure accuracy and record loss 226 | prec1, prec5 = accuracy(outputs.data, targets.data, topk=(1, 5)) 227 | losses.update(loss.item(), inputs.size(0)) 228 | top1.update(prec1.item(), inputs.size(0)) 229 | top5.update(prec5.item(), inputs.size(0)) 230 | 231 | # compute gradient and do SGD step 232 | optimizer.zero_grad() 233 | loss.backward() 234 | optimizer.step() 235 | 236 | # measure elapsed time 237 | batch_time.update(time.time() - end) 238 | end = time.time() 239 | 240 | # plot progress 241 | bar.suffix = '({batch}/{size}) Data: {data:.3f}s | Batch: {bt:.3f}s | Total: {total:} | ETA: {eta:} | Loss: {loss:.4f} | top1: {top1: .4f} | top5: {top5: .4f}'.format( 242 | batch=batch_idx + 1, 243 | size=len(trainloader), 244 | data=data_time.avg, 245 | bt=batch_time.avg, 246 | total=bar.elapsed_td, 247 | eta=bar.eta_td, 248 | loss=losses.avg, 249 | top1=top1.avg, 250 | top5=top5.avg, 251 | ) 252 | bar.next() 253 | bar.finish() 254 | return (losses.avg, top1.avg) 255 | 256 | def test(testloader, net, model, criterion, epoch, use_cuda, device): 257 | global best_acc 258 | 259 | batch_time = AverageMeter() 260 | data_time = AverageMeter() 261 | losses = AverageMeter() 262 | top1 = AverageMeter() 263 | top5 = AverageMeter() 264 | 265 | # switch to evaluate mode 266 | net.eval() 267 | model.eval() 268 | 269 | end = time.time() 270 | bar = Bar('Processing', max=len(testloader)) 271 | for batch_idx, (inputs, targets) in enumerate(testloader): 272 | # measure data loading time 273 | data_time.update(time.time() - end) 274 | 275 | if use_cuda: 276 | inputs, targets = inputs.to(device), targets.to(device) 277 | 278 | # compute output 279 | f1, f2 = net(inputs, inputs, out_feat_keys=['conv2']) 280 | 281 | out_mean = f1[:, :192] 282 | out_var = f1[:, 192:] 283 | std = torch.exp(0.5*out_var) 284 | feats = [] 285 | for _ in range(5): 286 | eps = torch.rand_like(std) 287 | feat = eps.mul(std * 0.001).add_(out_mean) 288 | feats.append(feat) 289 | 290 | feat = feats[0] 291 | for ii in range(1, 5): 292 | feat += feats[ii] 293 | 294 | feat = feat / 5. 295 | 296 | outputs = model(feat) 297 | loss = criterion(outputs, targets) 298 | 299 | # measure accuracy and record loss 300 | prec1, prec5 = accuracy(outputs.data, targets.data, topk=(1, 5)) 301 | losses.update(loss.item(), inputs.size(0)) 302 | top1.update(prec1.item(), inputs.size(0)) 303 | top5.update(prec5.item(), inputs.size(0)) 304 | 305 | # measure elapsed time 306 | batch_time.update(time.time() - end) 307 | end = time.time() 308 | 309 | # plot progress 310 | bar.suffix = '({batch}/{size}) Data: {data:.3f}s | Batch: {bt:.3f}s | Total: {total:} | ETA: {eta:} | Loss: {loss:.4f} | top1: {top1: .4f} | top5: {top5: .4f}'.format( 311 | batch=batch_idx + 1, 312 | size=len(testloader), 313 | data=data_time.avg, 314 | bt=batch_time.avg, 315 | total=bar.elapsed_td, 316 | eta=bar.eta_td, 317 | loss=losses.avg, 318 | top1=top1.avg, 319 | top5=top5.avg, 320 | ) 321 | bar.next() 322 | bar.finish() 323 | return (losses.avg, top1.avg) 324 | 325 | def save_checkpoint(state, is_best, checkpoint='checkpoint', filename='checkpoint.pth.tar'): 326 | filepath = os.path.join(checkpoint, filename) 327 | torch.save(state, filepath) 328 | if is_best: 329 | shutil.copyfile(filepath, os.path.join(checkpoint, 'model_best.pth.tar')) 330 | 331 | def adjust_learning_rate(optimizer, epoch): 332 | global state 333 | if epoch in args.schedule: 334 | state['lr'] *= args.gamma 335 | for param_group in optimizer.param_groups: 336 | param_group['lr'] = state['lr'] 337 | 338 | if __name__ == '__main__': 339 | main() 340 | -------------------------------------------------------------------------------- /cifar/dataset.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from PIL import Image, PILLOW_VERSION 3 | import os 4 | import os.path 5 | import numpy as np 6 | import sys 7 | import numbers 8 | import random 9 | if sys.version_info[0] == 2: 10 | import cPickle as pickle 11 | else: 12 | import pickle 13 | 14 | import torch 15 | import torch.utils.data as data 16 | from torchvision.datasets.utils import download_url, check_integrity 17 | from torchvision.transforms.functional import _get_inverse_affine_matrix 18 | import math 19 | 20 | 21 | class CIFAR10(data.Dataset): 22 | """`CIFAR10 `_ Dataset. 23 | 24 | Args: 25 | root (string): Root directory of dataset where directory 26 | ``cifar-10-batches-py`` exists or will be saved to if download is set to True. 27 | train (bool, optional): If True, creates dataset from training set, otherwise 28 | creates from test set. 29 | transform (callable, optional): A function/transform that takes in an PIL image 30 | and returns a transformed version. E.g, ``transforms.RandomCrop`` 31 | target_transform (callable, optional): A function/transform that takes in the 32 | target and transforms it. 33 | download (bool, optional): If true, downloads the dataset from the internet and 34 | puts it in root directory. If dataset is already downloaded, it is not 35 | downloaded again. 36 | 37 | """ 38 | base_folder = 'cifar-10-batches-py' 39 | url = "https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz" 40 | filename = "cifar-10-python.tar.gz" 41 | tgz_md5 = 'c58f30108f718f92721af3b95e74349a' 42 | train_list = [ 43 | ['data_batch_1', 'c99cafc152244af753f735de768cd75f'], 44 | ['data_batch_2', 'd4bba439e000b95fd0a9bffe97cbabec'], 45 | ['data_batch_3', '54ebc095f3ab1f0389bbae665268c751'], 46 | ['data_batch_4', '634d18415352ddfa80567beed471001a'], 47 | ['data_batch_5', '482c414d41f54cd18b22e5b47cb7c3cb'], 48 | ] 49 | 50 | test_list = [ 51 | ['test_batch', '40351d587109b95175f43aff81a1287e'], 52 | ] 53 | 54 | def __init__(self, root, shift=6, scale=None, resample=False, fillcolor=0, train=True, 55 | transform_pre=None, transform=None, target_transform=None, matrix_transform=None, 56 | download=False): 57 | self.root = os.path.expanduser(root) 58 | self.transform_pre = transform_pre 59 | self.transform = transform 60 | self.target_transform = target_transform 61 | self.matrix_transform = matrix_transform 62 | self.train = train # training set or test set 63 | 64 | if download: 65 | self.download() 66 | 67 | if not self._check_integrity(): 68 | raise RuntimeError('Dataset not found or corrupted.' + 69 | ' You can use download=True to download it') 70 | 71 | # now load the picked numpy arrays 72 | if self.train: 73 | self.train_data = [] 74 | self.train_labels = [] 75 | for fentry in self.train_list: 76 | f = fentry[0] 77 | file = os.path.join(self.root, self.base_folder, f) 78 | fo = open(file, 'rb') 79 | if sys.version_info[0] == 2: 80 | entry = pickle.load(fo) 81 | else: 82 | entry = pickle.load(fo, encoding='latin1') 83 | self.train_data.append(entry['data']) 84 | if 'labels' in entry: 85 | self.train_labels += entry['labels'] 86 | else: 87 | self.train_labels += entry['fine_labels'] 88 | fo.close() 89 | 90 | self.train_data = np.concatenate(self.train_data) 91 | self.train_data = self.train_data.reshape((50000, 3, 32, 32)) 92 | self.train_data = self.train_data.transpose((0, 2, 3, 1)) # convert to HWC 93 | else: 94 | f = self.test_list[0][0] 95 | file = os.path.join(self.root, self.base_folder, f) 96 | fo = open(file, 'rb') 97 | if sys.version_info[0] == 2: 98 | entry = pickle.load(fo) 99 | else: 100 | entry = pickle.load(fo, encoding='latin1') 101 | self.test_data = entry['data'] 102 | if 'labels' in entry: 103 | self.test_labels = entry['labels'] 104 | else: 105 | self.test_labels = entry['fine_labels'] 106 | fo.close() 107 | self.test_data = self.test_data.reshape((10000, 3, 32, 32)) 108 | self.test_data = self.test_data.transpose((0, 2, 3, 1)) # convert to HWC 109 | 110 | #projective transformation 111 | if scale is not None: 112 | assert isinstance(scale, (tuple, list)) and len(scale) == 2, \ 113 | "scale should be a list or tuple and it must be of length 2." 114 | for s in scale: 115 | if s <= 0: 116 | raise ValueError("scale values should be positive") 117 | self.scale = scale 118 | 119 | self.shift = shift 120 | 121 | self.resample = resample 122 | self.fillcolor = fillcolor 123 | 124 | @staticmethod 125 | def find_coeffs(pa, pb): 126 | matrix = [] 127 | for p1, p2 in zip(pa, pb): 128 | matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]]) 129 | matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]]) 130 | 131 | A = np.matrix(matrix, dtype=np.float) 132 | B = np.array(pb).reshape(8) 133 | 134 | res = np.dot(np.linalg.inv(A.T * A) * A.T, B) 135 | return np.array(res).reshape(8) 136 | 137 | def __getitem__(self, index): 138 | """ 139 | Args: 140 | index (int): Index 141 | 142 | Returns: 143 | tuple: (image, target) where target is index of the target class. 144 | """ 145 | if self.train: 146 | img1, target = self.train_data[index], self.train_labels[index] 147 | else: 148 | img1, target = self.test_data[index], self.test_labels[index] 149 | 150 | # doing this so that it is consistent with all other datasets 151 | # to return a PIL Image 152 | img1 = Image.fromarray(img1) 153 | if self.transform_pre is not None: 154 | img1 = self.transform_pre(img1) 155 | 156 | # projective transformation on image2 157 | width, height = img1.size 158 | center = (img1.size[0] * 0.5 + 0.5, img1.size[1] * 0.5 + 0.5) 159 | shift = [float(random.randint(-int(self.shift), int(self.shift))) for ii in range(8)] 160 | scale = random.uniform(self.scale[0], self.scale[1]) 161 | rotation = random.randint(0,3) 162 | 163 | pts = [((0-center[0])*scale+center[0], (0-center[1])*scale+center[1]), 164 | ((width-center[0])*scale+center[0], (0-center[1])*scale+center[1]), 165 | ((width-center[0])*scale+center[0], (height-center[1])*scale+center[1]), 166 | ((0-center[0])*scale+center[0], (height-center[1])*scale+center[1])] 167 | pts = [pts[(ii+rotation)%4] for ii in range(4)] 168 | pts = [(pts[ii][0]+shift[2*ii], pts[ii][1]+shift[2*ii+1]) for ii in range(4)] 169 | 170 | coeffs = self.find_coeffs( 171 | pts, 172 | [(0, 0), (width, 0), (width, height), (0, height)] 173 | ) 174 | 175 | kwargs = {"fillcolor": self.fillcolor} if PILLOW_VERSION[0] == '5' else {} 176 | img2 = img1.transform((width, height), Image.PERSPECTIVE, coeffs, self.resample, **kwargs) 177 | 178 | if self.transform is not None: 179 | img1 = self.transform(img1) 180 | img2 = self.transform(img2) 181 | 182 | if self.target_transform is not None: 183 | target = self.target_transform(target) 184 | 185 | coeffs = torch.from_numpy(np.array(coeffs, np.float32, copy=False)).view(8, 1, 1) 186 | 187 | if self.matrix_transform is not None: 188 | coeffs = self.matrix_transform(coeffs) 189 | 190 | return img1, img2, coeffs, target 191 | 192 | 193 | def __len__(self): 194 | if self.train: 195 | return len(self.train_data) 196 | else: 197 | return len(self.test_data) 198 | 199 | def _check_integrity(self): 200 | root = self.root 201 | for fentry in (self.train_list + self.test_list): 202 | filename, md5 = fentry[0], fentry[1] 203 | fpath = os.path.join(root, self.base_folder, filename) 204 | if not check_integrity(fpath, md5): 205 | return False 206 | return True 207 | 208 | def download(self): 209 | import tarfile 210 | 211 | if self._check_integrity(): 212 | print('Files already downloaded and verified') 213 | return 214 | 215 | root = self.root 216 | download_url(self.url, root, self.filename, self.tgz_md5) 217 | 218 | # extract file 219 | cwd = os.getcwd() 220 | tar = tarfile.open(os.path.join(root, self.filename), "r:gz") 221 | os.chdir(root) 222 | tar.extractall() 223 | tar.close() 224 | os.chdir(cwd) 225 | 226 | def __repr__(self): 227 | fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' 228 | fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) 229 | tmp = 'train' if self.train is True else 'test' 230 | fmt_str += ' Split: {}\n'.format(tmp) 231 | fmt_str += ' Root Location: {}\n'.format(self.root) 232 | tmp = ' Transforms (if any): ' 233 | fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 234 | tmp = ' Target Transforms (if any): ' 235 | fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) 236 | return fmt_str -------------------------------------------------------------------------------- /cifar/get_mean_std.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import sys 3 | from PIL import Image 4 | import random 5 | 6 | def find_coeffs(pa, pb): 7 | matrix = [] 8 | for p1, p2 in zip(pa, pb): 9 | matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]]) 10 | matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]]) 11 | 12 | A = numpy.matrix(matrix, dtype=numpy.float) 13 | B = numpy.array(pb).reshape(8) 14 | 15 | res = numpy.dot(numpy.linalg.inv(A.T * A) * A.T, B) 16 | return numpy.array(res).reshape(8) 17 | 18 | all_coeffs = [] 19 | for kk in range(500000): 20 | width, height = (32, 32) 21 | center = (32 * 0.5 + 0.5, 32 * 0.5 + 0.5) 22 | 23 | shift = [float(random.randint(-4, 4)) for ii in range(8)] 24 | scale = random.uniform(0.8,1.2) 25 | 26 | pts = [((0-center[0])*scale+center[0], (0-center[1])*scale+center[1]), 27 | ((width-center[0])*scale+center[0], (0-center[1])*scale+center[1]), 28 | ((width-center[0])*scale+center[0], (height-center[1])*scale+center[1]), 29 | ((0-center[0])*scale+center[0], (height-center[1])*scale+center[1])] 30 | 31 | rotation = random.randint(0,3) 32 | pts = [pts[(ii+rotation)%4] for ii in range(4)] 33 | pts = [(pts[ii][0]+shift[2*ii], pts[ii][1]+shift[2*ii+1]) for ii in range(4)] 34 | 35 | coeffs = find_coeffs( 36 | pts, 37 | [(0, 0), (width, 0), (width, height), (0, height)] 38 | ) 39 | all_coeffs += [coeffs] 40 | 41 | all_coeffs = numpy.asarray(all_coeffs, dtype='float32') 42 | mean = numpy.mean(all_coeffs, axis=0, keepdims=True) 43 | std = numpy.std(all_coeffs, axis=0, keepdims=True) 44 | print(mean) 45 | print(std) 46 | 47 | mean = numpy.asarray([[0,0,16,0,0,16,5.5e-4,5.5e-4]], dtype='float32') 48 | std = numpy.asarray([[0.763,0.763,17,0.763,0.763,17,6.12e-3,6.12e-3]], dtype='float32') 49 | 50 | all_coeffs_norm = (all_coeffs - mean) / std 51 | print(numpy.max(all_coeffs_norm, axis=0)) 52 | print(numpy.min(all_coeffs_norm, axis=0)) 53 | -------------------------------------------------------------------------------- /cifar/main.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import argparse 3 | import os 4 | import random 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.parallel 8 | import torch.backends.cudnn as cudnn 9 | import torch.optim as optim 10 | import torch.utils.data 11 | import torchvision.transforms as transforms 12 | import torchvision.utils as vutils 13 | 14 | from NetworkInNetwork import Regressor 15 | from dataset import CIFAR10 16 | import PIL 17 | 18 | 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('--dataroot', default='/home/liheng/cifar10', help='path to dataset') 21 | parser.add_argument('--workers', type=int, help='number of data loading workers', default=4) 22 | parser.add_argument('--batchSize', type=int, default=512, help='input batch size') 23 | parser.add_argument('--imageSize', type=int, default=32, help='the height / width of the input image to network') 24 | parser.add_argument('--niter', type=int, default=4500, help='number of epochs to train for') 25 | parser.add_argument('--lr', type=float, default=0.001, help='learning rate, default=0.0002') 26 | parser.add_argument('--beta1', type=float, default=0.5, help='beta1 for adam. default=0.5') 27 | parser.add_argument('--cuda', action='store_true', help='enables cuda') 28 | parser.add_argument('--ngpu', type=int, default=1, help='number of GPUs to use') 29 | parser.add_argument('--net', default='', help="path to net (to continue training)") 30 | parser.add_argument('--optimizer', default='', help="path to optimizer (to continue training)") 31 | parser.add_argument('--outf', default='.', help='folder to output images and model checkpoints') 32 | parser.add_argument('--manualSeed', type=int, help='manual seed') 33 | parser.add_argument('--shift', type=float, default=4) 34 | parser.add_argument('--shrink', type=float, default=0.8) 35 | parser.add_argument('--enlarge', type=float, default=1.2) 36 | parser.add_argument('--lrMul', type=float, default=10.) 37 | parser.add_argument('--divide', type=float, default=1000.) 38 | 39 | opt = parser.parse_args() 40 | print(opt) 41 | 42 | try: 43 | os.makedirs(opt.outf) 44 | except OSError: 45 | pass 46 | 47 | if opt.manualSeed is None: 48 | opt.manualSeed = random.randint(1, 10000) 49 | print("Random Seed: ", opt.manualSeed) 50 | random.seed(opt.manualSeed) 51 | torch.manual_seed(opt.manualSeed) 52 | 53 | cudnn.benchmark = True 54 | 55 | if torch.cuda.is_available() and not opt.cuda: 56 | print("WARNING: You have a CUDA device, so you should probably run with --cuda") 57 | 58 | train_dataset = CIFAR10(root=opt.dataroot, shift=opt.shift, scale=(opt.shrink, opt.enlarge), fillcolor=(128,128,128), download=True, resample=PIL.Image.BILINEAR, 59 | matrix_transform=transforms.Compose([ 60 | transforms.Normalize((0., 0., 16., 0., 0., 16., 0., 0.), (1., 1., 20., 1., 1., 20., 0.015, 0.015)), 61 | ]), 62 | transform_pre=transforms.Compose([ 63 | transforms.RandomCrop(32, padding=4), 64 | transforms.RandomHorizontalFlip(), 65 | ]), 66 | transform=transforms.Compose([ 67 | transforms.ToTensor(), 68 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 69 | ])) 70 | 71 | test_dataset = CIFAR10(root=opt.dataroot, shift=opt.shift, scale=(opt.shrink, opt.enlarge), fillcolor=(128,128,128), download=True, train=False, resample=PIL.Image.BILINEAR, 72 | matrix_transform=transforms.Compose([ 73 | transforms.Normalize((0., 0., 16., 0., 0., 16., 0., 0.), (1., 1., 20., 1., 1., 20., 0.015, 0.015)), 74 | ]), 75 | transform_pre=transforms.Compose([ 76 | transforms.RandomCrop(32, padding=4), 77 | transforms.RandomHorizontalFlip(), 78 | ]), 79 | transform=transforms.Compose([ 80 | transforms.ToTensor(), 81 | transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), 82 | ])) 83 | 84 | 85 | assert train_dataset 86 | assert test_dataset 87 | train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=opt.batchSize, 88 | shuffle=True, num_workers=int(opt.workers)) 89 | test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=opt.batchSize, 90 | shuffle=False, num_workers=int(opt.workers)) 91 | 92 | device = torch.device("cuda:0" if opt.cuda else "cpu") 93 | ngpu = int(opt.ngpu) 94 | 95 | net = Regressor(_num_stages=4, _use_avg_on_conv3=False).to(device) 96 | if opt.cuda: 97 | net = torch.nn.DataParallel(net, device_ids=range(ngpu)) 98 | 99 | if opt.net != '': 100 | net.load_state_dict(torch.load(opt.net)) 101 | 102 | print(net) 103 | 104 | criterion = nn.MSELoss() 105 | 106 | # setup optimizer 107 | fc2_params = list(map(id, net.module.fc2.parameters())) 108 | base_params = filter(lambda p: id(p) not in fc2_params, net.parameters()) 109 | 110 | optimizer = optim.SGD([{'params':base_params}, {'params':net.module.fc2.parameters(), 'lr': opt.lr*opt.lrMul}], lr=opt.lr, momentum=0.9, weight_decay=5e-4, nesterov=True) 111 | if opt.optimizer != '': 112 | optimizer.load_state_dict(torch.load(opt.optimizer)) 113 | 114 | for epoch in range(opt.niter): 115 | if epoch >= 50 and epoch < 3240: 116 | optimizer.param_groups[0]['lr'] = opt.lr * 5 117 | optimizer.param_groups[1]['lr'] = opt.lr * opt.lrMul 118 | elif epoch >= 3240 and epoch < 3480: 119 | optimizer.param_groups[0]['lr'] = opt.lr * 5 * 0.2 120 | optimizer.param_groups[1]['lr'] = opt.lr * opt.lrMul 121 | elif epoch >= 3480 and epoch < 3640: 122 | optimizer.param_groups[0]['lr'] = opt.lr * 5 * 0.04 123 | optimizer.param_groups[1]['lr'] = opt.lr * opt.lrMul * 0.001 124 | elif epoch >= 3640 and epoch < 3800: 125 | optimizer.param_groups[0]['lr'] = opt.lr * 5 * 0.008 126 | optimizer.param_groups[1]['lr'] = opt.lr * opt.lrMul * 0.001 127 | elif epoch >= 3800 and epoch < 4000: 128 | optimizer.param_groups[0]['lr'] = opt.lr * 5 * 0.0016 129 | optimizer.param_groups[1]['lr'] = opt.lr * opt.lrMul * 0.001 130 | elif epoch >= 4000: 131 | optimizer.param_groups[0]['lr'] = opt.lr * 5 * 0.0016 - opt.lr * 5 * 3e-6 * (epoch - 4000) 132 | optimizer.param_groups[1]['lr'] = opt.lr * opt.lrMul * 0.001 133 | 134 | for i, data in enumerate(train_dataloader, 0): 135 | net.zero_grad() 136 | img1 = data[0].to(device) 137 | img2 = data[1].to(device) 138 | matrix = data[2].to(device) 139 | matrix = matrix.view(-1, 8) 140 | 141 | batch_size = img1.size(0) 142 | f1, f2, output_mu, output_logvar = net(img1, img2) 143 | output_logvar = output_logvar / opt.divide 144 | std_sqr = torch.exp(output_logvar) 145 | 146 | err_matrix = criterion(output_mu, matrix) 147 | err = (torch.sum(output_logvar) + torch.sum((output_mu - matrix)*(output_mu - matrix) / (std_sqr + 1e-4))) / batch_size 148 | err.backward() 149 | optimizer.step() 150 | 151 | print('[%d/%d][%d/%d] Loss: %.4f, Loss_matrix: %.4f' 152 | % (epoch, opt.niter, i, len(train_dataloader), 153 | err.item(), err_matrix.item())) 154 | 155 | 156 | # do checkpointing 157 | if epoch % 100 == 99: 158 | torch.save(net.state_dict(), '%s/net_epoch_%d.pth' % (opt.outf, epoch)) 159 | torch.save(optimizer.state_dict(), '%s/optimizer_epoch_%d.pth' % (opt.outf, epoch)) -------------------------------------------------------------------------------- /cifar/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """Useful utils 2 | """ 3 | from .misc import * 4 | from .logger import * 5 | from .visualize import * 6 | from .eval import * 7 | 8 | # progress bar 9 | import os, sys 10 | sys.path.append(os.path.join(os.path.dirname(__file__), "progress")) 11 | from progress.bar import Bar as Bar -------------------------------------------------------------------------------- /cifar/utils/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/__init__.pyc -------------------------------------------------------------------------------- /cifar/utils/eval.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, absolute_import 2 | 3 | __all__ = ['accuracy'] 4 | 5 | def accuracy(output, target, topk=(1,)): 6 | """Computes the precision@k for the specified values of k""" 7 | maxk = max(topk) 8 | batch_size = target.size(0) 9 | 10 | _, pred = output.topk(maxk, 1, True, True) 11 | pred = pred.t() 12 | correct = pred.eq(target.view(1, -1).expand_as(pred)) 13 | 14 | res = [] 15 | for k in topk: 16 | correct_k = correct[:k].view(-1).float().sum(0) 17 | res.append(correct_k.mul_(100.0 / batch_size)) 18 | return res -------------------------------------------------------------------------------- /cifar/utils/eval.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/eval.pyc -------------------------------------------------------------------------------- /cifar/utils/logger.py: -------------------------------------------------------------------------------- 1 | # A simple torch style logger 2 | # (C) Wei YANG 2017 3 | from __future__ import absolute_import 4 | import matplotlib.pyplot as plt 5 | import os 6 | import sys 7 | import numpy as np 8 | 9 | __all__ = ['Logger', 'LoggerMonitor', 'savefig'] 10 | 11 | def savefig(fname, dpi=None): 12 | dpi = 150 if dpi == None else dpi 13 | plt.savefig(fname, dpi=dpi) 14 | 15 | def plot_overlap(logger, names=None): 16 | names = logger.names if names == None else names 17 | numbers = logger.numbers 18 | for _, name in enumerate(names): 19 | x = np.arange(len(numbers[name])) 20 | plt.plot(x, np.asarray(numbers[name])) 21 | return [logger.title + '(' + name + ')' for name in names] 22 | 23 | class Logger(object): 24 | '''Save training process to log file with simple plot function.''' 25 | def __init__(self, fpath, title=None, resume=False): 26 | self.file = None 27 | self.resume = resume 28 | self.title = '' if title == None else title 29 | if fpath is not None: 30 | if resume: 31 | self.file = open(fpath, 'r') 32 | name = self.file.readline() 33 | self.names = name.rstrip().split('\t') 34 | self.numbers = {} 35 | for _, name in enumerate(self.names): 36 | self.numbers[name] = [] 37 | 38 | for numbers in self.file: 39 | numbers = numbers.rstrip().split('\t') 40 | for i in range(0, len(numbers)): 41 | self.numbers[self.names[i]].append(numbers[i]) 42 | self.file.close() 43 | self.file = open(fpath, 'a') 44 | else: 45 | self.file = open(fpath, 'w') 46 | 47 | def set_names(self, names): 48 | if self.resume: 49 | pass 50 | # initialize numbers as empty list 51 | self.numbers = {} 52 | self.names = names 53 | for _, name in enumerate(self.names): 54 | self.file.write(name) 55 | self.file.write('\t') 56 | self.numbers[name] = [] 57 | self.file.write('\n') 58 | self.file.flush() 59 | 60 | 61 | def append(self, numbers): 62 | assert len(self.names) == len(numbers), 'Numbers do not match names' 63 | for index, num in enumerate(numbers): 64 | self.file.write("{0:.6f}".format(num)) 65 | self.file.write('\t') 66 | self.numbers[self.names[index]].append(num) 67 | self.file.write('\n') 68 | self.file.flush() 69 | 70 | def plot(self, names=None): 71 | names = self.names if names == None else names 72 | numbers = self.numbers 73 | for _, name in enumerate(names): 74 | x = np.arange(len(numbers[name])) 75 | plt.plot(x, np.asarray(numbers[name])) 76 | plt.legend([self.title + '(' + name + ')' for name in names]) 77 | plt.grid(True) 78 | 79 | def close(self): 80 | if self.file is not None: 81 | self.file.close() 82 | 83 | class LoggerMonitor(object): 84 | '''Load and visualize multiple logs.''' 85 | def __init__ (self, paths): 86 | '''paths is a distionary with {name:filepath} pair''' 87 | self.loggers = [] 88 | for title, path in paths.items(): 89 | logger = Logger(path, title=title, resume=True) 90 | self.loggers.append(logger) 91 | 92 | def plot(self, names=None): 93 | plt.figure() 94 | plt.subplot(121) 95 | legend_text = [] 96 | for logger in self.loggers: 97 | legend_text += plot_overlap(logger, names) 98 | plt.legend(legend_text, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) 99 | plt.grid(True) 100 | 101 | if __name__ == '__main__': 102 | # # Example 103 | # logger = Logger('test.txt') 104 | # logger.set_names(['Train loss', 'Valid loss','Test loss']) 105 | 106 | # length = 100 107 | # t = np.arange(length) 108 | # train_loss = np.exp(-t / 10.0) + np.random.rand(length) * 0.1 109 | # valid_loss = np.exp(-t / 10.0) + np.random.rand(length) * 0.1 110 | # test_loss = np.exp(-t / 10.0) + np.random.rand(length) * 0.1 111 | 112 | # for i in range(0, length): 113 | # logger.append([train_loss[i], valid_loss[i], test_loss[i]]) 114 | # logger.plot() 115 | 116 | # Example: logger monitor 117 | paths = { 118 | 'resadvnet20':'/home/wyang/code/pytorch-classification/checkpoint/cifar10/resadvnet20/log.txt', 119 | 'resadvnet32':'/home/wyang/code/pytorch-classification/checkpoint/cifar10/resadvnet32/log.txt', 120 | 'resadvnet44':'/home/wyang/code/pytorch-classification/checkpoint/cifar10/resadvnet44/log.txt', 121 | } 122 | 123 | field = ['Valid Acc.'] 124 | 125 | monitor = LoggerMonitor(paths) 126 | monitor.plot(names=field) 127 | savefig('test.eps') -------------------------------------------------------------------------------- /cifar/utils/logger.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/logger.pyc -------------------------------------------------------------------------------- /cifar/utils/misc.py: -------------------------------------------------------------------------------- 1 | '''Some helper functions for PyTorch, including: 2 | - get_mean_and_std: calculate the mean and std value of dataset. 3 | - msr_init: net parameter initialization. 4 | - progress_bar: progress bar mimic xlua.progress. 5 | ''' 6 | import errno 7 | import os 8 | import sys 9 | import time 10 | import math 11 | 12 | import torch.nn as nn 13 | import torch.nn.init as init 14 | from torch.autograd import Variable 15 | 16 | __all__ = ['get_mean_and_std', 'init_params', 'mkdir_p', 'AverageMeter'] 17 | 18 | 19 | def get_mean_and_std(dataset): 20 | '''Compute the mean and std value of dataset.''' 21 | dataloader = trainloader = torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=True, num_workers=2) 22 | 23 | mean = torch.zeros(3) 24 | std = torch.zeros(3) 25 | print('==> Computing mean and std..') 26 | for inputs, targets in dataloader: 27 | for i in range(3): 28 | mean[i] += inputs[:,i,:,:].mean() 29 | std[i] += inputs[:,i,:,:].std() 30 | mean.div_(len(dataset)) 31 | std.div_(len(dataset)) 32 | return mean, std 33 | 34 | def init_params(net): 35 | '''Init layer parameters.''' 36 | for m in net.modules(): 37 | if isinstance(m, nn.Conv2d): 38 | init.kaiming_normal(m.weight, mode='fan_out') 39 | if m.bias: 40 | init.constant(m.bias, 0) 41 | elif isinstance(m, nn.BatchNorm2d): 42 | init.constant(m.weight, 1) 43 | init.constant(m.bias, 0) 44 | elif isinstance(m, nn.Linear): 45 | init.normal(m.weight, std=1e-3) 46 | if m.bias: 47 | init.constant(m.bias, 0) 48 | 49 | def mkdir_p(path): 50 | '''make dir if not exist''' 51 | try: 52 | os.makedirs(path) 53 | except OSError as exc: # Python >2.5 54 | if exc.errno == errno.EEXIST and os.path.isdir(path): 55 | pass 56 | else: 57 | raise 58 | 59 | class AverageMeter(object): 60 | """Computes and stores the average and current value 61 | Imported from https://github.com/pytorch/examples/blob/master/imagenet/main.py#L247-L262 62 | """ 63 | def __init__(self): 64 | self.reset() 65 | 66 | def reset(self): 67 | self.val = 0 68 | self.avg = 0 69 | self.sum = 0 70 | self.count = 0 71 | 72 | def update(self, val, n=1): 73 | self.val = val 74 | self.sum += val * n 75 | self.count += n 76 | self.avg = self.sum / self.count -------------------------------------------------------------------------------- /cifar/utils/misc.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/misc.pyc -------------------------------------------------------------------------------- /cifar/utils/progress/LICENSE: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2012 Giorgos Verigakis 2 | # 3 | # Permission to use, copy, modify, and distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /cifar/utils/progress/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst LICENSE 2 | -------------------------------------------------------------------------------- /cifar/utils/progress/README.rst: -------------------------------------------------------------------------------- 1 | Easy progress reporting for Python 2 | ================================== 3 | 4 | |pypi| 5 | 6 | |demo| 7 | 8 | .. |pypi| image:: https://img.shields.io/pypi/v/progress.svg 9 | .. |demo| image:: https://raw.github.com/verigak/progress/master/demo.gif 10 | :alt: Demo 11 | 12 | Bars 13 | ---- 14 | 15 | There are 7 progress bars to choose from: 16 | 17 | - ``Bar`` 18 | - ``ChargingBar`` 19 | - ``FillingSquaresBar`` 20 | - ``FillingCirclesBar`` 21 | - ``IncrementalBar`` 22 | - ``PixelBar`` 23 | - ``ShadyBar`` 24 | 25 | To use them, just call ``next`` to advance and ``finish`` to finish: 26 | 27 | .. code-block:: python 28 | 29 | from progress.bar import Bar 30 | 31 | bar = Bar('Processing', max=20) 32 | for i in range(20): 33 | # Do some work 34 | bar.next() 35 | bar.finish() 36 | 37 | The result will be a bar like the following: :: 38 | 39 | Processing |############# | 42/100 40 | 41 | To simplify the common case where the work is done in an iterator, you can 42 | use the ``iter`` method: 43 | 44 | .. code-block:: python 45 | 46 | for i in Bar('Processing').iter(it): 47 | # Do some work 48 | 49 | Progress bars are very customizable, you can change their width, their fill 50 | character, their suffix and more: 51 | 52 | .. code-block:: python 53 | 54 | bar = Bar('Loading', fill='@', suffix='%(percent)d%%') 55 | 56 | This will produce a bar like the following: :: 57 | 58 | Loading |@@@@@@@@@@@@@ | 42% 59 | 60 | You can use a number of template arguments in ``message`` and ``suffix``: 61 | 62 | ========== ================================ 63 | Name Value 64 | ========== ================================ 65 | index current value 66 | max maximum value 67 | remaining max - index 68 | progress index / max 69 | percent progress * 100 70 | avg simple moving average time per item (in seconds) 71 | elapsed elapsed time in seconds 72 | elapsed_td elapsed as a timedelta (useful for printing as a string) 73 | eta avg * remaining 74 | eta_td eta as a timedelta (useful for printing as a string) 75 | ========== ================================ 76 | 77 | Instead of passing all configuration options on instatiation, you can create 78 | your custom subclass: 79 | 80 | .. code-block:: python 81 | 82 | class FancyBar(Bar): 83 | message = 'Loading' 84 | fill = '*' 85 | suffix = '%(percent).1f%% - %(eta)ds' 86 | 87 | You can also override any of the arguments or create your own: 88 | 89 | .. code-block:: python 90 | 91 | class SlowBar(Bar): 92 | suffix = '%(remaining_hours)d hours remaining' 93 | @property 94 | def remaining_hours(self): 95 | return self.eta // 3600 96 | 97 | 98 | Spinners 99 | ======== 100 | 101 | For actions with an unknown number of steps you can use a spinner: 102 | 103 | .. code-block:: python 104 | 105 | from progress.spinner import Spinner 106 | 107 | spinner = Spinner('Loading ') 108 | while state != 'FINISHED': 109 | # Do some work 110 | spinner.next() 111 | 112 | There are 5 predefined spinners: 113 | 114 | - ``Spinner`` 115 | - ``PieSpinner`` 116 | - ``MoonSpinner`` 117 | - ``LineSpinner`` 118 | - ``PixelSpinner`` 119 | 120 | 121 | Other 122 | ===== 123 | 124 | There are a number of other classes available too, please check the source or 125 | subclass one of them to create your own. 126 | 127 | 128 | License 129 | ======= 130 | 131 | progress is licensed under ISC 132 | -------------------------------------------------------------------------------- /cifar/utils/progress/progress/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2012 Giorgos Verigakis 2 | # 3 | # Permission to use, copy, modify, and distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | from __future__ import division 16 | 17 | from collections import deque 18 | from datetime import timedelta 19 | from math import ceil 20 | from sys import stderr 21 | from time import time 22 | 23 | 24 | __version__ = '1.3' 25 | 26 | 27 | class Infinite(object): 28 | file = stderr 29 | sma_window = 10 # Simple Moving Average window 30 | 31 | def __init__(self, *args, **kwargs): 32 | self.index = 0 33 | self.start_ts = time() 34 | self.avg = 0 35 | self._ts = self.start_ts 36 | self._xput = deque(maxlen=self.sma_window) 37 | for key, val in kwargs.items(): 38 | setattr(self, key, val) 39 | 40 | def __getitem__(self, key): 41 | if key.startswith('_'): 42 | return None 43 | return getattr(self, key, None) 44 | 45 | @property 46 | def elapsed(self): 47 | return int(time() - self.start_ts) 48 | 49 | @property 50 | def elapsed_td(self): 51 | return timedelta(seconds=self.elapsed) 52 | 53 | def update_avg(self, n, dt): 54 | if n > 0: 55 | self._xput.append(dt / n) 56 | self.avg = sum(self._xput) / len(self._xput) 57 | 58 | def update(self): 59 | pass 60 | 61 | def start(self): 62 | pass 63 | 64 | def finish(self): 65 | pass 66 | 67 | def next(self, n=1): 68 | now = time() 69 | dt = now - self._ts 70 | self.update_avg(n, dt) 71 | self._ts = now 72 | self.index = self.index + n 73 | self.update() 74 | 75 | def iter(self, it): 76 | try: 77 | for x in it: 78 | yield x 79 | self.next() 80 | finally: 81 | self.finish() 82 | 83 | 84 | class Progress(Infinite): 85 | def __init__(self, *args, **kwargs): 86 | super(Progress, self).__init__(*args, **kwargs) 87 | self.max = kwargs.get('max', 100) 88 | 89 | @property 90 | def eta(self): 91 | return int(ceil(self.avg * self.remaining)) 92 | 93 | @property 94 | def eta_td(self): 95 | return timedelta(seconds=self.eta) 96 | 97 | @property 98 | def percent(self): 99 | return self.progress * 100 100 | 101 | @property 102 | def progress(self): 103 | return min(1, self.index / self.max) 104 | 105 | @property 106 | def remaining(self): 107 | return max(self.max - self.index, 0) 108 | 109 | def start(self): 110 | self.update() 111 | 112 | def goto(self, index): 113 | incr = index - self.index 114 | self.next(incr) 115 | 116 | def iter(self, it): 117 | try: 118 | self.max = len(it) 119 | except TypeError: 120 | pass 121 | 122 | try: 123 | for x in it: 124 | yield x 125 | self.next() 126 | finally: 127 | self.finish() 128 | -------------------------------------------------------------------------------- /cifar/utils/progress/progress/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/progress/progress/__init__.pyc -------------------------------------------------------------------------------- /cifar/utils/progress/progress/bar.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2012 Giorgos Verigakis 4 | # 5 | # Permission to use, copy, modify, and distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | from __future__ import unicode_literals 18 | from . import Progress 19 | from .helpers import WritelnMixin 20 | 21 | 22 | class Bar(WritelnMixin, Progress): 23 | width = 32 24 | message = '' 25 | suffix = '%(index)d/%(max)d' 26 | bar_prefix = ' |' 27 | bar_suffix = '| ' 28 | empty_fill = ' ' 29 | fill = '#' 30 | hide_cursor = True 31 | 32 | def update(self): 33 | filled_length = int(self.width * self.progress) 34 | empty_length = self.width - filled_length 35 | 36 | message = self.message % self 37 | bar = self.fill * filled_length 38 | empty = self.empty_fill * empty_length 39 | suffix = self.suffix % self 40 | line = ''.join([message, self.bar_prefix, bar, empty, self.bar_suffix, 41 | suffix]) 42 | self.writeln(line) 43 | 44 | 45 | class ChargingBar(Bar): 46 | suffix = '%(percent)d%%' 47 | bar_prefix = ' ' 48 | bar_suffix = ' ' 49 | empty_fill = '∙' 50 | fill = '█' 51 | 52 | 53 | class FillingSquaresBar(ChargingBar): 54 | empty_fill = '▢' 55 | fill = '▣' 56 | 57 | 58 | class FillingCirclesBar(ChargingBar): 59 | empty_fill = '◯' 60 | fill = '◉' 61 | 62 | 63 | class IncrementalBar(Bar): 64 | phases = (' ', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█') 65 | 66 | def update(self): 67 | nphases = len(self.phases) 68 | filled_len = self.width * self.progress 69 | nfull = int(filled_len) # Number of full chars 70 | phase = int((filled_len - nfull) * nphases) # Phase of last char 71 | nempty = self.width - nfull # Number of empty chars 72 | 73 | message = self.message % self 74 | bar = self.phases[-1] * nfull 75 | current = self.phases[phase] if phase > 0 else '' 76 | empty = self.empty_fill * max(0, nempty - len(current)) 77 | suffix = self.suffix % self 78 | line = ''.join([message, self.bar_prefix, bar, current, empty, 79 | self.bar_suffix, suffix]) 80 | self.writeln(line) 81 | 82 | 83 | class PixelBar(IncrementalBar): 84 | phases = ('⡀', '⡄', '⡆', '⡇', '⣇', '⣧', '⣷', '⣿') 85 | 86 | 87 | class ShadyBar(IncrementalBar): 88 | phases = (' ', '░', '▒', '▓', '█') 89 | -------------------------------------------------------------------------------- /cifar/utils/progress/progress/bar.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/progress/progress/bar.pyc -------------------------------------------------------------------------------- /cifar/utils/progress/progress/counter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2012 Giorgos Verigakis 4 | # 5 | # Permission to use, copy, modify, and distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | from __future__ import unicode_literals 18 | from . import Infinite, Progress 19 | from .helpers import WriteMixin 20 | 21 | 22 | class Counter(WriteMixin, Infinite): 23 | message = '' 24 | hide_cursor = True 25 | 26 | def update(self): 27 | self.write(str(self.index)) 28 | 29 | 30 | class Countdown(WriteMixin, Progress): 31 | hide_cursor = True 32 | 33 | def update(self): 34 | self.write(str(self.remaining)) 35 | 36 | 37 | class Stack(WriteMixin, Progress): 38 | phases = (' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█') 39 | hide_cursor = True 40 | 41 | def update(self): 42 | nphases = len(self.phases) 43 | i = min(nphases - 1, int(self.progress * nphases)) 44 | self.write(self.phases[i]) 45 | 46 | 47 | class Pie(Stack): 48 | phases = ('○', '◔', '◑', '◕', '●') 49 | -------------------------------------------------------------------------------- /cifar/utils/progress/progress/helpers.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2012 Giorgos Verigakis 2 | # 3 | # Permission to use, copy, modify, and distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | from __future__ import print_function 16 | 17 | 18 | HIDE_CURSOR = '\x1b[?25l' 19 | SHOW_CURSOR = '\x1b[?25h' 20 | 21 | 22 | class WriteMixin(object): 23 | hide_cursor = False 24 | 25 | def __init__(self, message=None, **kwargs): 26 | super(WriteMixin, self).__init__(**kwargs) 27 | self._width = 0 28 | if message: 29 | self.message = message 30 | 31 | if self.file.isatty(): 32 | if self.hide_cursor: 33 | print(HIDE_CURSOR, end='', file=self.file) 34 | print(self.message, end='', file=self.file) 35 | self.file.flush() 36 | 37 | def write(self, s): 38 | if self.file.isatty(): 39 | b = '\b' * self._width 40 | c = s.ljust(self._width) 41 | print(b + c, end='', file=self.file) 42 | self._width = max(self._width, len(s)) 43 | self.file.flush() 44 | 45 | def finish(self): 46 | if self.file.isatty() and self.hide_cursor: 47 | print(SHOW_CURSOR, end='', file=self.file) 48 | 49 | 50 | class WritelnMixin(object): 51 | hide_cursor = False 52 | 53 | def __init__(self, message=None, **kwargs): 54 | super(WritelnMixin, self).__init__(**kwargs) 55 | if message: 56 | self.message = message 57 | 58 | if self.file.isatty() and self.hide_cursor: 59 | print(HIDE_CURSOR, end='', file=self.file) 60 | 61 | def clearln(self): 62 | if self.file.isatty(): 63 | print('\r\x1b[K', end='', file=self.file) 64 | 65 | def writeln(self, line): 66 | if self.file.isatty(): 67 | self.clearln() 68 | print(line, end='', file=self.file) 69 | self.file.flush() 70 | 71 | def finish(self): 72 | if self.file.isatty(): 73 | print(file=self.file) 74 | if self.hide_cursor: 75 | print(SHOW_CURSOR, end='', file=self.file) 76 | 77 | 78 | from signal import signal, SIGINT 79 | from sys import exit 80 | 81 | 82 | class SigIntMixin(object): 83 | """Registers a signal handler that calls finish on SIGINT""" 84 | 85 | def __init__(self, *args, **kwargs): 86 | super(SigIntMixin, self).__init__(*args, **kwargs) 87 | signal(SIGINT, self._sigint_handler) 88 | 89 | def _sigint_handler(self, signum, frame): 90 | self.finish() 91 | exit(0) 92 | -------------------------------------------------------------------------------- /cifar/utils/progress/progress/helpers.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/progress/progress/helpers.pyc -------------------------------------------------------------------------------- /cifar/utils/progress/progress/spinner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2012 Giorgos Verigakis 4 | # 5 | # Permission to use, copy, modify, and distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | from __future__ import unicode_literals 18 | from . import Infinite 19 | from .helpers import WriteMixin 20 | 21 | 22 | class Spinner(WriteMixin, Infinite): 23 | message = '' 24 | phases = ('-', '\\', '|', '/') 25 | hide_cursor = True 26 | 27 | def update(self): 28 | i = self.index % len(self.phases) 29 | self.write(self.phases[i]) 30 | 31 | 32 | class PieSpinner(Spinner): 33 | phases = ['◷', '◶', '◵', '◴'] 34 | 35 | 36 | class MoonSpinner(Spinner): 37 | phases = ['◑', '◒', '◐', '◓'] 38 | 39 | 40 | class LineSpinner(Spinner): 41 | phases = ['⎺', '⎻', '⎼', '⎽', '⎼', '⎻'] 42 | 43 | class PixelSpinner(Spinner): 44 | phases = ['⣾','⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽'] 45 | -------------------------------------------------------------------------------- /cifar/utils/progress/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup 4 | 5 | import progress 6 | 7 | 8 | setup( 9 | name='progress', 10 | version=progress.__version__, 11 | description='Easy to use progress bars', 12 | long_description=open('README.rst').read(), 13 | author='Giorgos Verigakis', 14 | author_email='verigak@gmail.com', 15 | url='http://github.com/verigak/progress/', 16 | license='ISC', 17 | packages=['progress'], 18 | classifiers=[ 19 | 'Environment :: Console', 20 | 'Intended Audience :: Developers', 21 | 'License :: OSI Approved :: ISC License (ISCL)', 22 | 'Programming Language :: Python :: 2.6', 23 | 'Programming Language :: Python :: 2.7', 24 | 'Programming Language :: Python :: 3.3', 25 | 'Programming Language :: Python :: 3.4', 26 | 'Programming Language :: Python :: 3.5', 27 | 'Programming Language :: Python :: 3.6', 28 | ] 29 | ) 30 | -------------------------------------------------------------------------------- /cifar/utils/progress/test_progress.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | 5 | import random 6 | import time 7 | 8 | from progress.bar import (Bar, ChargingBar, FillingSquaresBar, 9 | FillingCirclesBar, IncrementalBar, PixelBar, 10 | ShadyBar) 11 | from progress.spinner import (Spinner, PieSpinner, MoonSpinner, LineSpinner, 12 | PixelSpinner) 13 | from progress.counter import Counter, Countdown, Stack, Pie 14 | 15 | 16 | def sleep(): 17 | t = 0.01 18 | t += t * random.uniform(-0.1, 0.1) # Add some variance 19 | time.sleep(t) 20 | 21 | 22 | for bar_cls in (Bar, ChargingBar, FillingSquaresBar, FillingCirclesBar): 23 | suffix = '%(index)d/%(max)d [%(elapsed)d / %(eta)d / %(eta_td)s]' 24 | bar = bar_cls(bar_cls.__name__, suffix=suffix) 25 | for i in bar.iter(range(200)): 26 | sleep() 27 | 28 | for bar_cls in (IncrementalBar, PixelBar, ShadyBar): 29 | suffix = '%(percent)d%% [%(elapsed_td)s / %(eta)d / %(eta_td)s]' 30 | bar = bar_cls(bar_cls.__name__, suffix=suffix) 31 | for i in bar.iter(range(200)): 32 | sleep() 33 | 34 | for spin in (Spinner, PieSpinner, MoonSpinner, LineSpinner, PixelSpinner): 35 | for i in spin(spin.__name__ + ' ').iter(range(100)): 36 | sleep() 37 | print() 38 | 39 | for singleton in (Counter, Countdown, Stack, Pie): 40 | for i in singleton(singleton.__name__ + ' ').iter(range(100)): 41 | sleep() 42 | print() 43 | 44 | bar = IncrementalBar('Random', suffix='%(index)d') 45 | for i in range(100): 46 | bar.goto(random.randint(0, 100)) 47 | sleep() 48 | bar.finish() 49 | -------------------------------------------------------------------------------- /cifar/utils/visualize.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import torch 3 | import torch.nn as nn 4 | import torchvision 5 | import torchvision.transforms as transforms 6 | import numpy as np 7 | from .misc import * 8 | 9 | __all__ = ['make_image', 'show_batch', 'show_mask', 'show_mask_single'] 10 | 11 | # functions to show an image 12 | def make_image(img, mean=(0,0,0), std=(1,1,1)): 13 | for i in range(0, 3): 14 | img[i] = img[i] * std[i] + mean[i] # unnormalize 15 | npimg = img.numpy() 16 | return np.transpose(npimg, (1, 2, 0)) 17 | 18 | def gauss(x,a,b,c): 19 | return torch.exp(-torch.pow(torch.add(x,-b),2).div(2*c*c)).mul(a) 20 | 21 | def colorize(x): 22 | ''' Converts a one-channel grayscale image to a color heatmap image ''' 23 | if x.dim() == 2: 24 | torch.unsqueeze(x, 0, out=x) 25 | if x.dim() == 3: 26 | cl = torch.zeros([3, x.size(1), x.size(2)]) 27 | cl[0] = gauss(x,.5,.6,.2) + gauss(x,1,.8,.3) 28 | cl[1] = gauss(x,1,.5,.3) 29 | cl[2] = gauss(x,1,.2,.3) 30 | cl[cl.gt(1)] = 1 31 | elif x.dim() == 4: 32 | cl = torch.zeros([x.size(0), 3, x.size(2), x.size(3)]) 33 | cl[:,0,:,:] = gauss(x,.5,.6,.2) + gauss(x,1,.8,.3) 34 | cl[:,1,:,:] = gauss(x,1,.5,.3) 35 | cl[:,2,:,:] = gauss(x,1,.2,.3) 36 | return cl 37 | 38 | def show_batch(images, Mean=(2, 2, 2), Std=(0.5,0.5,0.5)): 39 | images = make_image(torchvision.utils.make_grid(images), Mean, Std) 40 | plt.imshow(images) 41 | plt.show() 42 | 43 | 44 | def show_mask_single(images, mask, Mean=(2, 2, 2), Std=(0.5,0.5,0.5)): 45 | im_size = images.size(2) 46 | 47 | # save for adding mask 48 | im_data = images.clone() 49 | for i in range(0, 3): 50 | im_data[:,i,:,:] = im_data[:,i,:,:] * Std[i] + Mean[i] # unnormalize 51 | 52 | images = make_image(torchvision.utils.make_grid(images), Mean, Std) 53 | plt.subplot(2, 1, 1) 54 | plt.imshow(images) 55 | plt.axis('off') 56 | 57 | # for b in range(mask.size(0)): 58 | # mask[b] = (mask[b] - mask[b].min())/(mask[b].max() - mask[b].min()) 59 | mask_size = mask.size(2) 60 | # print('Max %f Min %f' % (mask.max(), mask.min())) 61 | mask = (upsampling(mask, scale_factor=im_size/mask_size)) 62 | # mask = colorize(upsampling(mask, scale_factor=im_size/mask_size)) 63 | # for c in range(3): 64 | # mask[:,c,:,:] = (mask[:,c,:,:] - Mean[c])/Std[c] 65 | 66 | # print(mask.size()) 67 | mask = make_image(torchvision.utils.make_grid(0.3*im_data+0.7*mask.expand_as(im_data))) 68 | # mask = make_image(torchvision.utils.make_grid(0.3*im_data+0.7*mask), Mean, Std) 69 | plt.subplot(2, 1, 2) 70 | plt.imshow(mask) 71 | plt.axis('off') 72 | 73 | def show_mask(images, masklist, Mean=(2, 2, 2), Std=(0.5,0.5,0.5)): 74 | im_size = images.size(2) 75 | 76 | # save for adding mask 77 | im_data = images.clone() 78 | for i in range(0, 3): 79 | im_data[:,i,:,:] = im_data[:,i,:,:] * Std[i] + Mean[i] # unnormalize 80 | 81 | images = make_image(torchvision.utils.make_grid(images), Mean, Std) 82 | plt.subplot(1+len(masklist), 1, 1) 83 | plt.imshow(images) 84 | plt.axis('off') 85 | 86 | for i in range(len(masklist)): 87 | mask = masklist[i].data.cpu() 88 | # for b in range(mask.size(0)): 89 | # mask[b] = (mask[b] - mask[b].min())/(mask[b].max() - mask[b].min()) 90 | mask_size = mask.size(2) 91 | # print('Max %f Min %f' % (mask.max(), mask.min())) 92 | mask = (upsampling(mask, scale_factor=im_size/mask_size)) 93 | # mask = colorize(upsampling(mask, scale_factor=im_size/mask_size)) 94 | # for c in range(3): 95 | # mask[:,c,:,:] = (mask[:,c,:,:] - Mean[c])/Std[c] 96 | 97 | # print(mask.size()) 98 | mask = make_image(torchvision.utils.make_grid(0.3*im_data+0.7*mask.expand_as(im_data))) 99 | # mask = make_image(torchvision.utils.make_grid(0.3*im_data+0.7*mask), Mean, Std) 100 | plt.subplot(1+len(masklist), 1, i+2) 101 | plt.imshow(mask) 102 | plt.axis('off') 103 | 104 | 105 | 106 | # x = torch.zeros(1, 3, 3) 107 | # out = colorize(x) 108 | # out_im = make_image(out) 109 | # plt.imshow(out_im) 110 | # plt.show() -------------------------------------------------------------------------------- /cifar/utils/visualize.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/cifar/utils/visualize.pyc -------------------------------------------------------------------------------- /resources/AVT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maple-research-lab/AVT-pytorch/d92aaa60fd25783f8844dd0bb292c9a78e18713f/resources/AVT.PNG --------------------------------------------------------------------------------