File size: 12,632 Bytes
a6b4c35 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | #!/usr/bin/python
'''
Defines a generic wrapper class for all the network models
Utilizes params.py to create, initiate, load and train the network.
'''
import torch
import numpy as np
from collections import OrderedDict
import scipy.io
from torch.autograd import Variable
import os
from Generators import *
from utils import *
class ModelADT():
def name(self):
return 'Pix2PixModel'
def initialize(self, opt):
self.opt = opt
# self.gpu_ids = opt.gpu_ids
gpu_ids = []
for i in range(torch.cuda.device_count()):
gpu_ids.append(str(i))
print(gpu_ids)
self.gpu_ids = gpu_ids
self.isTrain = opt.isTrain
self.loss_weight = opt.lambda_L
self.reg_loss_weight = opt.lambda_reg
self.cross_loss_weight = opt.lambda_cross
self.device = torch.device('cuda:{}'.format(self.gpu_ids[0])) # if self.gpu_ids else torch.device('cpu')
print(self.device)
self.model_name = self.opt.name
self.save_dir = os.path.join(self.opt.checkpoints_save_dir, self.model_name)
self.load_dir = os.path.join(self.opt.checkpoints_load_dir, self.model_name)
self.results_save_dir = opt.results_dir
self.loss_names = []
self.visual_names = []
self.image_paths = []
self.loss_names = ['loss_criterion']
self.visual_names = ['output']
self.net = get_model_funct(self.opt.net)(self.opt, self.gpu_ids)
self.net = self.net.to(self.device)
if self.isTrain:
if self.opt.loss_type == "L2":
self.loss_criterion = torch.nn.MSELoss()
elif self.opt.loss_type == "L1":
self.loss_criterion = torch.nn.L1Loss()
elif self.opt.loss_type == "L1_sumL2":
self.loss_criterion = torch.nn.L1Loss()
elif self.opt.loss_type == "L2_sumL2":
self.loss_criterion = torch.nn.MSELoss()
elif self.opt.loss_type == "L2_sumL1":
self.loss_criterion = torch.nn.MSELoss()
elif self.opt.loss_type == "L2_offset_loss":
self.loss_criterion = torch.nn.MSELoss()
elif self.opt.loss_type == "L1_offset_loss":
self.loss_criterion = torch.nn.L1Loss()
elif self.opt.loss_type == "L1_sumL2_cross":
self.loss_criterion = torch.nn.MSELoss()
elif self.opt.loss_type == "L2_sumL2_cross":
self.loss_criterion = torch.nn.MSELoss()
self.cross_loss_criterion = torch.nn.NLLLoss()
# initialize optimizers
self.optimizers = []
self.optimizer = torch.optim.Adam(self.net.parameters(),lr=opt.lr, betas=(opt.beta1, 0.999), weight_decay=opt.weight_decay)
self.optimizers.append(self.optimizer)
# load and print networks; create schedulers
def setup(self, opt, parser=None):
if self.isTrain:
self.schedulers = [get_scheduler(optimizer, opt) for optimizer in self.optimizers]
if not self.isTrain or opt.continue_train:
self.load_networks(opt.starting_epoch_count)
if self.isTrain and opt.continue_train:
self.load_training_state(opt.starting_epoch_count)
self.print_networks(opt.verbose)
# make models eval mode during test time
def eval(self):
self.net.eval()
# used in test time, wrapping `forward` in no_grad() so we don't save
# intermediate steps for backprop
def test(self):
with torch.no_grad():
self.forward()
def save_outputs(self):
if not os.path.exists(self.results_save_dir):
os.makedirs(self.results_save_dir, exist_ok=True)
to_save_dict = {}
for tensor in self.visual_names:
tensor_val = getattr(self, tensor).data.cpu().numpy()
to_save_dict[tensor] = tensor_val
scipy.io.savemat(self.results_save_dir+".mat", mdict=to_save_dict)
# update learning rate (called once every epoch)
def update_learning_rate(self):
for scheduler in self.schedulers:
scheduler.step()
lr = self.optimizers[0].param_groups[0]['lr']
print('learning rate = %.7f' % lr)
# return visualization images. train.py will display these images, and save the images to a html
def get_current_visuals(self):
visual_ret = OrderedDict()
for name in self.visual_names:
if isinstance(name, str):
visual_ret[name] = getattr(self, name)
return visual_ret
# return traning losses/errors. train.py will print out these errors as debugging information
def get_current_losses(self):
errors_ret = OrderedDict()
for name in self.loss_names:
if isinstance(name, str):
# float(...) works for both scalar tensor and float number
errors_ret[name] = float(getattr(self, 'loss_' + name))
return errors_ret
# save models to the disk
def save_networks(self, epoch):
name = self.model_name
save_filename = '%s_net_%s.pth' % (epoch, name)
if not os.path.exists(self.save_dir):
os.makedirs(self.save_dir)
save_path = os.path.join(self.save_dir, save_filename)
net = self.net
print(save_path)
print('net'+name)
if len(self.gpu_ids) > 0 and torch.cuda.is_available() and hasattr(net, 'module'):
torch.save(net.module.cpu().state_dict(), save_path)
else:
torch.save(net.cpu().state_dict(), save_path)
net.to(self.device)
# save optimizer, scheduler, and RNG state
if self.isTrain:
optim_filename = '%s_optim_%s.pth' % (epoch, self.model_name)
optim_path = os.path.join(self.save_dir, optim_filename)
save_dict = {
'optimizer': self.optimizer.state_dict(),
'scheduler': self.schedulers[0].state_dict() if self.schedulers else None,
'rng_torch': torch.random.get_rng_state(),
'rng_numpy': np.random.get_state(),
}
if torch.cuda.is_available():
save_dict['rng_cuda'] = torch.cuda.get_rng_state_all()
torch.save(save_dict, optim_path)
def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0):
key = keys[i]
if i + 1 == len(keys): # at the end, pointing to a parameter/buffer
if module.__class__.__name__.startswith('InstanceNorm') and (key == 'running_mean' or key == 'running_var'):
if getattr(module, key) is None:
state_dict.pop('.'.join(keys))
if module.__class__.__name__.startswith('InstanceNorm') and (key == 'num_batches_tracked'):
state_dict.pop('.'.join(keys))
else:
self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1)
# load models from the disk
def load_networks(self, epoch, load_dir=""):
"""
epoch (int/str): epoch index / "best" / "latest"
"""
assert isinstance(epoch,int) or epoch=="best" or epoch=="latest"
load_filename = f'{epoch}_net_{self.model_name}.pth'
if load_dir:
# use given load dir
load_path = os.path.join(load_dir, self.model_name, load_filename)
else:
# use default load dir
load_path = os.path.join(self.load_dir, load_filename)
net = self.net
if isinstance(net, torch.nn.DataParallel):
net = net.module
print('loading the model from %s' % load_path)
# if you are using PyTorch newer than 0.4 (e.g., built from
# GitHub source), you can remove str() on self.device
state_dict = torch.load(load_path, weights_only=False)
if hasattr(state_dict, '_metadata'):
del state_dict._metadata
# patch InstanceNorm checkpoints prior to 0.4
print(state_dict.keys())
for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop
self.__patch_instance_norm_state_dict(state_dict, net, key.split('.'))
net.load_state_dict(state_dict)
net = net.to(self.device)
# load optimizer and scheduler state from disk
def load_training_state(self, epoch):
optim_filename = f'{epoch}_optim_{self.model_name}.pth'
load_path = os.path.join(self.load_dir, optim_filename)
if os.path.exists(load_path):
print(f'loading optimizer/scheduler from {load_path}')
state = torch.load(load_path, weights_only=False)
self.optimizer.load_state_dict(state['optimizer'])
if state.get('scheduler') and self.schedulers:
self.schedulers[0].load_state_dict(state['scheduler'])
# Restore RNG states for session continuity
if 'rng_torch' in state:
torch.random.set_rng_state(state['rng_torch'])
if 'rng_numpy' in state:
np.random.set_state(state['rng_numpy'])
if 'rng_cuda' in state and torch.cuda.is_available():
torch.cuda.set_rng_state_all(state['rng_cuda'])
else:
print(f'No optimizer state found at {load_path}, starting fresh')
# print network information
def print_networks(self, verbose):
print('---------- Networks initialized -------------')
net = self.net
name = self.model_name
num_params = 0
for param in net.parameters():
num_params += param.numel()
if verbose:
print(net)
print('[Network %s] Total number of parameters : %.3f M' % (name, num_params / 1e6))
print('-----------------------------------------------')
# set requies_grad=Fasle to avoid computation
def set_requires_grad(self, nets, requires_grad=False):
if not isinstance(nets, list):
nets = [nets]
for net in nets:
if net is not None:
for param in net.parameters():
param.requires_grad = requires_grad
# Set the input and target data for the network to train on/evaluate against
def set_data(self, input, target, convert=False, shuffle_channel=False):
shape_in = input.shape
if shuffle_channel:
self.input = input[:,torch.randperm(shape_in[1]),:,:]
else:
self.input = input
self.target = target
if convert:
self.input, self.target = Variable(self.input), Variable(self.target)
self.input = self.input.to(self.device)
self.target = self.target.to(self.device)
# Define the forward pass to compute loss
def forward(self):
self.output = self.net(self.input)
if self.opt.loss_type != "NoLoss":
self.loss = self.loss_weight*self.loss_criterion(self.output, self.target)
if self.opt.loss_type == "L1_sumL2" or self.opt.loss_type == "L2_sumL2":
self.loss += self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
self.reg_loss = self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
if self.opt.loss_type == "L2_sumL1":
self.loss += self.reg_loss_weight*torch.norm(self.output,p=1).div(self.output.numel())
self.reg_loss = self.reg_loss_weight*torch.norm(self.output,p=1).div(self.output.numel())
if self.opt.loss_type == "L1_sumL2_cross" or self.opt.loss_type == "L2_sumL2_cross":
self.loss += self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
self.loss += self.cross_loss_weight*self.cross_loss_criterion(self.output.flatten(start_dim=1),self.target.flatten(start_dim=1))
if self.opt.loss_type == "L1_offset_loss" or self.opt.loss_type == "L2_offset_loss":
self.loss += self.reg_loss_weight*torch.norm(self.output).div(self.output.numel())
def backward(self):
self.loss.backward(retain_graph=True)
def optimize_parameters(self):
self.forward()
self.backward()
self.optimizer.step()
self.optimizer.zero_grad()
|