From f87530a15cdf92064297825b8b7a9e23da87f6a5 Mon Sep 17 00:00:00 2001 From: junyanz Date: Thu, 19 Oct 2017 19:19:39 -0700 Subject: fix small issue in learning rate policy --- models/networks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'models') diff --git a/models/networks.py b/models/networks.py index 2df58fe..0b8938d 100644 --- a/models/networks.py +++ b/models/networks.py @@ -87,8 +87,8 @@ def get_norm_layer(norm_type='instance'): def get_scheduler(optimizer, opt): if opt.lr_policy == 'lambda': - def lambda_rule(epoch): - lr_l = 1.0 - max(0, epoch - opt.niter) / float(opt.niter_decay+1) + def lambda_rule(epoch): # epoch ranges from [1, opt.niter+opt.niter_decay] + lr_l = 1.0 - max(0, epoch - opt.niter) / float(opt.niter_decay) return lr_l scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_rule) elif opt.lr_policy == 'step': -- cgit v1.2.3-70-g09d2 From 2a344ccd6f80ce0435d2c58ccfd94c76dd423b1a Mon Sep 17 00:00:00 2001 From: junyanz Date: Thu, 19 Oct 2017 19:35:11 -0700 Subject: update learning rate policy --- models/networks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'models') diff --git a/models/networks.py b/models/networks.py index 0b8938d..19169c5 100644 --- a/models/networks.py +++ b/models/networks.py @@ -88,7 +88,7 @@ def get_norm_layer(norm_type='instance'): def get_scheduler(optimizer, opt): if opt.lr_policy == 'lambda': def lambda_rule(epoch): # epoch ranges from [1, opt.niter+opt.niter_decay] - lr_l = 1.0 - max(0, epoch - opt.niter) / float(opt.niter_decay) + lr_l = 1.0 - max(0, epoch - opt.niter + 1) / float(opt.niter_decay + 1) return lr_l scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_rule) elif opt.lr_policy == 'step': -- cgit v1.2.3-70-g09d2 From 9d1bc76e6a4f791a25db1179c7c2b4c62a8d55cd Mon Sep 17 00:00:00 2001 From: junyanz Date: Thu, 19 Oct 2017 21:14:48 -0700 Subject: fix learning rate --- models/networks.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'models') diff --git a/models/networks.py b/models/networks.py index 19169c5..51e3f25 100644 --- a/models/networks.py +++ b/models/networks.py @@ -10,7 +10,6 @@ import numpy as np ############################################################################### - def weights_init_normal(m): classname = m.__class__.__name__ # print(classname) @@ -87,8 +86,8 @@ def get_norm_layer(norm_type='instance'): def get_scheduler(optimizer, opt): if opt.lr_policy == 'lambda': - def lambda_rule(epoch): # epoch ranges from [1, opt.niter+opt.niter_decay] - lr_l = 1.0 - max(0, epoch - opt.niter + 1) / float(opt.niter_decay + 1) + def lambda_rule(epoch): + lr_l = 1.0 - max(0, epoch + 1 + opt.epoch_count - opt.niter) / float(opt.niter_decay + 1) return lr_l scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_rule) elif opt.lr_policy == 'step': -- cgit v1.2.3-70-g09d2 From 1e0fbeaf5bc81c0b9e23655dc31d28c77505b7cd Mon Sep 17 00:00:00 2001 From: LambdaWill <574819595@qq.com> Date: Sat, 21 Oct 2017 12:34:44 +0800 Subject: Compatible with the latest version. Since the commit `Change device_id to device in python land #3133`, keyword `device_id` has been changed to `device` --- models/networks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'models') diff --git a/models/networks.py b/models/networks.py index 51e3f25..dca5489 100644 --- a/models/networks.py +++ b/models/networks.py @@ -118,7 +118,7 @@ def define_G(input_nc, output_nc, ngf, which_model_netG, norm='batch', use_dropo else: raise NotImplementedError('Generator model name [%s] is not recognized' % which_model_netG) if len(gpu_ids) > 0: - netG.cuda(device_id=gpu_ids[0]) + netG.cuda(device_id=gpu_ids[0]) # or netG.cuda(device=gpu_ids[0]) for latest version. init_weights(netG, init_type=init_type) return netG @@ -139,7 +139,7 @@ def define_D(input_nc, ndf, which_model_netD, raise NotImplementedError('Discriminator model name [%s] is not recognized' % which_model_netD) if use_gpu: - netD.cuda(device_id=gpu_ids[0]) + netD.cuda(device_id=gpu_ids[0]) # or netG.cuda(device=gpu_ids[0]) for latest version. init_weights(netD, init_type=init_type) return netD -- cgit v1.2.3-70-g09d2 From 9d0295bbb5d01ce40bd2792f72882128282f0338 Mon Sep 17 00:00:00 2001 From: LambdaWill <574819595@qq.com> Date: Sat, 21 Oct 2017 17:06:30 +0800 Subject: Update networks.py fix typo --- models/networks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'models') diff --git a/models/networks.py b/models/networks.py index dca5489..949659d 100644 --- a/models/networks.py +++ b/models/networks.py @@ -139,7 +139,7 @@ def define_D(input_nc, ndf, which_model_netD, raise NotImplementedError('Discriminator model name [%s] is not recognized' % which_model_netD) if use_gpu: - netD.cuda(device_id=gpu_ids[0]) # or netG.cuda(device=gpu_ids[0]) for latest version. + netD.cuda(device_id=gpu_ids[0]) # or netD.cuda(device=gpu_ids[0]) for latest version. init_weights(netD, init_type=init_type) return netD -- cgit v1.2.3-70-g09d2 From 343dda259b4b6a64a338fa61a9f1c70893b8fc7e Mon Sep 17 00:00:00 2001 From: LambdaWill <574819595@qq.com> Date: Tue, 24 Oct 2017 12:21:00 +0800 Subject: Update base_model.py --- models/base_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'models') diff --git a/models/base_model.py b/models/base_model.py index 446a903..d62d189 100644 --- a/models/base_model.py +++ b/models/base_model.py @@ -44,7 +44,7 @@ class BaseModel(): save_path = os.path.join(self.save_dir, save_filename) torch.save(network.cpu().state_dict(), save_path) if len(gpu_ids) and torch.cuda.is_available(): - network.cuda(device_id=gpu_ids[0]) + network.cuda(device_id=gpu_ids[0]) # network.cuda(device=gpu_ids[0]) for the latest version. # helper loading function that can be used by subclasses def load_network(self, network, network_label, epoch_label): -- cgit v1.2.3-70-g09d2 From d6cb5036a2a8b57f8c1a7cdc7e7cc80416d4ee78 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Mercier Date: Thu, 2 Nov 2017 18:00:10 -0400 Subject: gpu memory leaks --- models/cycle_gan_model.py | 81 +++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 28 deletions(-) (limited to 'models') diff --git a/models/cycle_gan_model.py b/models/cycle_gan_model.py index 29389db..ecb92dc 100644 --- a/models/cycle_gan_model.py +++ b/models/cycle_gan_model.py @@ -130,33 +130,58 @@ class CycleGANModel(BaseModel): # Identity loss if lambda_idt > 0: # G_A should be identity if real_B is fed. - self.idt_A = self.netG_A.forward(self.real_B) - self.loss_idt_A = self.criterionIdt(self.idt_A, self.real_B) * lambda_B * lambda_idt + idt_A = self.netG_A.forward(self.real_B) + loss_idt_A = self.criterionIdt(idt_A, self.real_B) * lambda_B * lambda_idt # G_B should be identity if real_A is fed. - self.idt_B = self.netG_B.forward(self.real_A) - self.loss_idt_B = self.criterionIdt(self.idt_B, self.real_A) * lambda_A * lambda_idt + idt_B = self.netG_B.forward(self.real_A) + loss_idt_B = self.criterionIdt(idt_B, self.real_A) * lambda_A * lambda_idt + + self.idt_A = idt_A.data + self.idt_B = idt_B.data + self.loss_idt_A = loss_idt_A.data[0] + self.loss_idt_B = loss_idt_B.data[0] + else: + loss_idt_A = 0 + loss_idt_B = 0 self.loss_idt_A = 0 self.loss_idt_B = 0 # GAN loss # D_A(G_A(A)) - self.fake_B = self.netG_A.forward(self.real_A) - pred_fake = self.netD_A.forward(self.fake_B) - self.loss_G_A = self.criterionGAN(pred_fake, True) + fake_B = self.netG_A.forward(self.real_A) + pred_fake = self.netD_A.forward(fake_B) + loss_G_A = self.criterionGAN(pred_fake, True) + # D_B(G_B(B)) - self.fake_A = self.netG_B.forward(self.real_B) - pred_fake = self.netD_B.forward(self.fake_A) - self.loss_G_B = self.criterionGAN(pred_fake, True) + fake_A = self.netG_B.forward(self.real_B) + pred_fake = self.netD_B.forward(fake_A) + loss_G_B = self.criterionGAN(pred_fake, True) + # Forward cycle loss - self.rec_A = self.netG_B.forward(self.fake_B) - self.loss_cycle_A = self.criterionCycle(self.rec_A, self.real_A) * lambda_A + rec_A = self.netG_B.forward(fake_B) + loss_cycle_A = self.criterionCycle(rec_A, self.real_A) * lambda_A + # Backward cycle loss - self.rec_B = self.netG_A.forward(self.fake_A) - self.loss_cycle_B = self.criterionCycle(self.rec_B, self.real_B) * lambda_B + rec_B = self.netG_A.forward(fake_A) + loss_cycle_B = self.criterionCycle(rec_B, self.real_B) * lambda_B + # combined loss - self.loss_G = self.loss_G_A + self.loss_G_B + self.loss_cycle_A + self.loss_cycle_B + self.loss_idt_A + self.loss_idt_B - self.loss_G.backward() + loss_G = loss_G_A + loss_G_B + loss_cycle_A + loss_cycle_B + loss_idt_A + loss_idt_B + loss_G.backward() + + self.fake_B = fake_B.data + self.fake_A = fake_A.data + self.rec_A = rec_A.data + self.rec_B = rec_B.data + + self.loss_G_A = loss_G_A.data[0] + self.loss_G_B = loss_G_B.data[0] + self.loss_cycle_A = loss_cycle_A.data[0] + self.loss_cycle_B = loss_cycle_B.data[0] + + + def optimize_parameters(self): # forward @@ -176,14 +201,14 @@ class CycleGANModel(BaseModel): def get_current_errors(self): D_A = self.loss_D_A.data[0] - G_A = self.loss_G_A.data[0] - Cyc_A = self.loss_cycle_A.data[0] + G_A = self.loss_G_A + Cyc_A = self.loss_cycle_A D_B = self.loss_D_B.data[0] - G_B = self.loss_G_B.data[0] - Cyc_B = self.loss_cycle_B.data[0] + G_B = self.loss_G_B + Cyc_B = self.loss_cycle_B if self.opt.identity > 0.0: - idt_A = self.loss_idt_A.data[0] - idt_B = self.loss_idt_B.data[0] + idt_A = self.loss_idt_A + idt_B = self.loss_idt_B return OrderedDict([('D_A', D_A), ('G_A', G_A), ('Cyc_A', Cyc_A), ('idt_A', idt_A), ('D_B', D_B), ('G_B', G_B), ('Cyc_B', Cyc_B), ('idt_B', idt_B)]) else: @@ -192,14 +217,14 @@ class CycleGANModel(BaseModel): def get_current_visuals(self): real_A = util.tensor2im(self.real_A.data) - fake_B = util.tensor2im(self.fake_B.data) - rec_A = util.tensor2im(self.rec_A.data) + fake_B = util.tensor2im(self.fake_B) + rec_A = util.tensor2im(self.rec_A) real_B = util.tensor2im(self.real_B.data) - fake_A = util.tensor2im(self.fake_A.data) - rec_B = util.tensor2im(self.rec_B.data) + fake_A = util.tensor2im(self.fake_A) + rec_B = util.tensor2im(self.rec_B) if self.opt.isTrain and self.opt.identity > 0.0: - idt_A = util.tensor2im(self.idt_A.data) - idt_B = util.tensor2im(self.idt_B.data) + idt_A = util.tensor2im(self.idt_A) + idt_B = util.tensor2im(self.idt_B) return OrderedDict([('real_A', real_A), ('fake_B', fake_B), ('rec_A', rec_A), ('idt_B', idt_B), ('real_B', real_B), ('fake_A', fake_A), ('rec_B', rec_B), ('idt_A', idt_A)]) else: -- cgit v1.2.3-70-g09d2 From c114f1234420a51458b601761ffe4a6fd1b406a7 Mon Sep 17 00:00:00 2001 From: Robert M Ochshorn Date: Fri, 3 Nov 2017 09:03:19 +0100 Subject: util.tensor2im takes data, not Variable --- models/cycle_gan_model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'models') diff --git a/models/cycle_gan_model.py b/models/cycle_gan_model.py index ecb92dc..ff7330b 100644 --- a/models/cycle_gan_model.py +++ b/models/cycle_gan_model.py @@ -217,11 +217,11 @@ class CycleGANModel(BaseModel): def get_current_visuals(self): real_A = util.tensor2im(self.real_A.data) - fake_B = util.tensor2im(self.fake_B) - rec_A = util.tensor2im(self.rec_A) + fake_B = util.tensor2im(self.fake_B.data) + rec_A = util.tensor2im(self.rec_A.data) real_B = util.tensor2im(self.real_B.data) - fake_A = util.tensor2im(self.fake_A) - rec_B = util.tensor2im(self.rec_B) + fake_A = util.tensor2im(self.fake_A.data) + rec_B = util.tensor2im(self.rec_B.data) if self.opt.isTrain and self.opt.identity > 0.0: idt_A = util.tensor2im(self.idt_A) idt_B = util.tensor2im(self.idt_B) -- cgit v1.2.3-70-g09d2 From 6b8e96c4bbd73a1e1d4e126d795a26fd0dae983c Mon Sep 17 00:00:00 2001 From: junyanz Date: Sat, 4 Nov 2017 02:27:18 -0700 Subject: add update_html_freq flag --- models/base_model.py | 3 +- models/cycle_gan_model.py | 88 +++++++++++++++++++++-------------------------- models/networks.py | 4 +-- models/pix2pix_model.py | 6 ++-- options/base_options.py | 2 +- options/train_options.py | 4 ++- train.py | 4 ++- util/image_pool.py | 2 ++ util/visualizer.py | 32 ++++++++++------- 9 files changed, 74 insertions(+), 71 deletions(-) (limited to 'models') diff --git a/models/base_model.py b/models/base_model.py index d62d189..646a014 100644 --- a/models/base_model.py +++ b/models/base_model.py @@ -44,13 +44,14 @@ class BaseModel(): save_path = os.path.join(self.save_dir, save_filename) torch.save(network.cpu().state_dict(), save_path) if len(gpu_ids) and torch.cuda.is_available(): - network.cuda(device_id=gpu_ids[0]) # network.cuda(device=gpu_ids[0]) for the latest version. + network.cuda(device_id=gpu_ids[0]) # network.cuda(device=gpu_ids[0]) for the latest version. # helper loading function that can be used by subclasses def load_network(self, network, network_label, epoch_label): save_filename = '%s_net_%s.pth' % (epoch_label, network_label) save_path = os.path.join(self.save_dir, save_filename) network.load_state_dict(torch.load(save_path)) + # update learning rate (called once every epoch) def update_learning_rate(self): for scheduler in self.schedulers: diff --git a/models/cycle_gan_model.py b/models/cycle_gan_model.py index ff7330b..71a447d 100644 --- a/models/cycle_gan_model.py +++ b/models/cycle_gan_model.py @@ -90,13 +90,15 @@ class CycleGANModel(BaseModel): self.real_B = Variable(self.input_B) def test(self): - self.real_A = Variable(self.input_A, volatile=True) - self.fake_B = self.netG_A.forward(self.real_A) - self.rec_A = self.netG_B.forward(self.fake_B) + real_A = Variable(self.input_A, volatile=True) + fake_B = self.netG_A.forward(real_A) + self.rec_A = self.netG_B.forward(fake_B).data + self.fake_B = fake_B.data - self.real_B = Variable(self.input_B, volatile=True) - self.fake_A = self.netG_B.forward(self.real_B) - self.rec_B = self.netG_A.forward(self.fake_A) + real_B = Variable(self.input_B, volatile=True) + fake_A = self.netG_B.forward(real_B) + self.rec_B = self.netG_A.forward(fake_A).data + self.fake_A = self.fake_A.data # get image paths def get_image_paths(self): @@ -117,11 +119,13 @@ class CycleGANModel(BaseModel): def backward_D_A(self): fake_B = self.fake_B_pool.query(self.fake_B) - self.loss_D_A = self.backward_D_basic(self.netD_A, self.real_B, fake_B) + loss_D_A = self.backward_D_basic(self.netD_A, self.real_B, fake_B) + self.loss_D_A = loss_D_A.data[0] def backward_D_B(self): fake_A = self.fake_A_pool.query(self.fake_A) - self.loss_D_B = self.backward_D_basic(self.netD_B, self.real_A, fake_A) + loss_D_B = self.backward_D_basic(self.netD_B, self.real_A, fake_A) + self.loss_D_B = loss_D_B.data[0] def backward_G(self): lambda_idt = self.opt.identity @@ -135,53 +139,49 @@ class CycleGANModel(BaseModel): # G_B should be identity if real_A is fed. idt_B = self.netG_B.forward(self.real_A) loss_idt_B = self.criterionIdt(idt_B, self.real_A) * lambda_A * lambda_idt - + self.idt_A = idt_A.data self.idt_B = idt_B.data self.loss_idt_A = loss_idt_A.data[0] - self.loss_idt_B = loss_idt_B.data[0] - + self.loss_idt_B = loss_idt_B.data[0] + else: loss_idt_A = 0 loss_idt_B = 0 self.loss_idt_A = 0 self.loss_idt_B = 0 - # GAN loss - # D_A(G_A(A)) + # GAN loss D_A(G_A(A)) fake_B = self.netG_A.forward(self.real_A) pred_fake = self.netD_A.forward(fake_B) loss_G_A = self.criterionGAN(pred_fake, True) - - # D_B(G_B(B)) + + # GAN loss D_B(G_B(B)) fake_A = self.netG_B.forward(self.real_B) pred_fake = self.netD_B.forward(fake_A) loss_G_B = self.criterionGAN(pred_fake, True) - + # Forward cycle loss rec_A = self.netG_B.forward(fake_B) loss_cycle_A = self.criterionCycle(rec_A, self.real_A) * lambda_A - + # Backward cycle loss rec_B = self.netG_A.forward(fake_A) loss_cycle_B = self.criterionCycle(rec_B, self.real_B) * lambda_B - + # combined loss loss_G = loss_G_A + loss_G_B + loss_cycle_A + loss_cycle_B + loss_idt_A + loss_idt_B loss_G.backward() - + self.fake_B = fake_B.data self.fake_A = fake_A.data self.rec_A = rec_A.data self.rec_B = rec_B.data - + self.loss_G_A = loss_G_A.data[0] self.loss_G_B = loss_G_B.data[0] self.loss_cycle_A = loss_cycle_A.data[0] self.loss_cycle_B = loss_cycle_B.data[0] - - - def optimize_parameters(self): # forward @@ -200,36 +200,26 @@ class CycleGANModel(BaseModel): self.optimizer_D_B.step() def get_current_errors(self): - D_A = self.loss_D_A.data[0] - G_A = self.loss_G_A - Cyc_A = self.loss_cycle_A - D_B = self.loss_D_B.data[0] - G_B = self.loss_G_B - Cyc_B = self.loss_cycle_B + ret_errors = OrderedDict([('D_A', self.loss_D_A), ('G_A', self.loss_G_A), ('Cyc_A', self.loss_cycle_A), + ('D_B', self.loss_D_B), ('G_B', self.loss_G_B), ('Cyc_B', self.loss_cycle_B)]) if self.opt.identity > 0.0: - idt_A = self.loss_idt_A - idt_B = self.loss_idt_B - return OrderedDict([('D_A', D_A), ('G_A', G_A), ('Cyc_A', Cyc_A), ('idt_A', idt_A), - ('D_B', D_B), ('G_B', G_B), ('Cyc_B', Cyc_B), ('idt_B', idt_B)]) - else: - return OrderedDict([('D_A', D_A), ('G_A', G_A), ('Cyc_A', Cyc_A), - ('D_B', D_B), ('G_B', G_B), ('Cyc_B', Cyc_B)]) + ret_errors['idt_A'] = self.loss_idt_A + ret_errors['idt_B'] = self.loss_idt_B + return ret_errors def get_current_visuals(self): - real_A = util.tensor2im(self.real_A.data) - fake_B = util.tensor2im(self.fake_B.data) - rec_A = util.tensor2im(self.rec_A.data) - real_B = util.tensor2im(self.real_B.data) - fake_A = util.tensor2im(self.fake_A.data) - rec_B = util.tensor2im(self.rec_B.data) + real_A = util.tensor2im(self.input_A) + fake_B = util.tensor2im(self.fake_B) + rec_A = util.tensor2im(self.rec_A) + real_B = util.tensor2im(self.input_B) + fake_A = util.tensor2im(self.fake_A) + rec_B = util.tensor2im(self.rec_B) + ret_visuals = OrderedDict([('real_A', real_A), ('fake_B', fake_B), ('rec_A', rec_A), + ('real_B', real_B), ('fake_A', fake_A), ('rec_B', rec_B)]) if self.opt.isTrain and self.opt.identity > 0.0: - idt_A = util.tensor2im(self.idt_A) - idt_B = util.tensor2im(self.idt_B) - return OrderedDict([('real_A', real_A), ('fake_B', fake_B), ('rec_A', rec_A), ('idt_B', idt_B), - ('real_B', real_B), ('fake_A', fake_A), ('rec_B', rec_B), ('idt_A', idt_A)]) - else: - return OrderedDict([('real_A', real_A), ('fake_B', fake_B), ('rec_A', rec_A), - ('real_B', real_B), ('fake_A', fake_A), ('rec_B', rec_B)]) + ret_visuals['idt_A'] = util.tensor2im(self.idt_A) + ret_visuals['idt_B'] = util.tensor2im(self.idt_B) + return ret_visuals def save(self, label): self.save_network(self.netG_A, 'G_A', label, self.gpu_ids) diff --git a/models/networks.py b/models/networks.py index 949659d..d071ac4 100644 --- a/models/networks.py +++ b/models/networks.py @@ -118,7 +118,7 @@ def define_G(input_nc, output_nc, ngf, which_model_netG, norm='batch', use_dropo else: raise NotImplementedError('Generator model name [%s] is not recognized' % which_model_netG) if len(gpu_ids) > 0: - netG.cuda(device_id=gpu_ids[0]) # or netG.cuda(device=gpu_ids[0]) for latest version. + netG.cuda(device_id=gpu_ids[0]) # or netG.cuda(device=gpu_ids[0]) for latest version. init_weights(netG, init_type=init_type) return netG @@ -139,7 +139,7 @@ def define_D(input_nc, ndf, which_model_netD, raise NotImplementedError('Discriminator model name [%s] is not recognized' % which_model_netD) if use_gpu: - netD.cuda(device_id=gpu_ids[0]) # or netD.cuda(device=gpu_ids[0]) for latest version. + netD.cuda(device_id=gpu_ids[0]) # or netD.cuda(device=gpu_ids[0]) for latest version. init_weights(netD, init_type=init_type) return netD diff --git a/models/pix2pix_model.py b/models/pix2pix_model.py index 18ba53f..8cd494f 100644 --- a/models/pix2pix_model.py +++ b/models/pix2pix_model.py @@ -87,12 +87,12 @@ class Pix2PixModel(BaseModel): # Fake # stop backprop to the generator by detaching fake_B fake_AB = self.fake_AB_pool.query(torch.cat((self.real_A, self.fake_B), 1)) - self.pred_fake = self.netD.forward(fake_AB.detach()) - self.loss_D_fake = self.criterionGAN(self.pred_fake, False) + pred_fake = self.netD.forward(fake_AB.detach()) + self.loss_D_fake = self.criterionGAN(pred_fake, False) # Real real_AB = torch.cat((self.real_A, self.real_B), 1) - self.pred_real = self.netD.forward(real_AB) + pred_real = self.netD.forward(real_AB) self.loss_D_real = self.criterionGAN(self.pred_real, True) # Combined loss diff --git a/options/base_options.py b/options/base_options.py index b2d5360..28ca673 100644 --- a/options/base_options.py +++ b/options/base_options.py @@ -3,6 +3,7 @@ import os from util import util import torch + class BaseOptions(): def __init__(self): self.parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) @@ -33,7 +34,6 @@ class BaseOptions(): self.parser.add_argument('--display_winsize', type=int, default=256, help='display window size') self.parser.add_argument('--display_id', type=int, default=1, help='window id of the web display') self.parser.add_argument('--display_port', type=int, default=8097, help='visdom port of the web display') - self.parser.add_argument('--display_single_pane_ncols', type=int, default=0, help='if positive, display all images in a single visdom web panel with certain number of images per row.') self.parser.add_argument('--no_dropout', action='store_true', help='no dropout for the generator') self.parser.add_argument('--max_dataset_size', type=int, default=float("inf"), help='Maximum number of samples allowed per dataset. If the dataset directory contains more than max_dataset_size, only a subset is loaded.') self.parser.add_argument('--resize_or_crop', type=str, default='resize_and_crop', help='scaling and cropping of images at load time [resize_and_crop|crop|scale_width|scale_width_and_crop]') diff --git a/options/train_options.py b/options/train_options.py index 32120ec..603d76a 100644 --- a/options/train_options.py +++ b/options/train_options.py @@ -5,6 +5,8 @@ class TrainOptions(BaseOptions): def initialize(self): BaseOptions.initialize(self) self.parser.add_argument('--display_freq', type=int, default=100, help='frequency of showing training results on screen') + self.parser.add_argument('--display_single_pane_ncols', type=int, default=0, help='if positive, display all images in a single visdom web panel with certain number of images per row.') + self.parser.add_argument('--update_html_freq', type=int, default=1000, help='frequency of saving training results to html') self.parser.add_argument('--print_freq', type=int, default=100, help='frequency of showing training results on console') self.parser.add_argument('--save_latest_freq', type=int, default=5000, help='frequency of saving the latest results') self.parser.add_argument('--save_epoch_freq', type=int, default=5, help='frequency of saving checkpoints at the end of epochs') @@ -23,6 +25,6 @@ class TrainOptions(BaseOptions): self.parser.add_argument('--no_html', action='store_true', help='do not save intermediate training results to [opt.checkpoints_dir]/[opt.name]/web/') self.parser.add_argument('--lr_policy', type=str, default='lambda', help='learning rate policy: lambda|step|plateau') self.parser.add_argument('--lr_decay_iters', type=int, default=50, help='multiply by a gamma every lr_decay_iters iterations') - self.parser.add_argument('--identity', type=float, default=0.0, help='use identity mapping. Setting identity other than 1 has an effect of scaling the weight of the identity mapping loss. For example, if the weight of the identity loss should be 10 times smaller than the weight of the reconstruction loss, please set optidentity = 0.1') + self.parser.add_argument('--identity', type=float, default=0.5, help='use identity mapping. Setting identity other than 1 has an effect of scaling the weight of the identity mapping loss. For example, if the weight of the identity loss should be 10 times smaller than the weight of the reconstruction loss, please set optidentity = 0.1') self.isTrain = True diff --git a/train.py b/train.py index 7d2a5e9..6dbd66b 100644 --- a/train.py +++ b/train.py @@ -20,13 +20,15 @@ for epoch in range(opt.epoch_count, opt.niter + opt.niter_decay + 1): for i, data in enumerate(dataset): iter_start_time = time.time() + visualizer.reset() total_steps += opt.batchSize epoch_iter += opt.batchSize model.set_input(data) model.optimize_parameters() if total_steps % opt.display_freq == 0: - visualizer.display_current_results(model.get_current_visuals(), epoch) + save_result = total_steps % opt.update_html_freq == 0 + visualizer.display_current_results(model.get_current_visuals(), epoch, save_result) if total_steps % opt.print_freq == 0: errors = model.get_current_errors() diff --git a/util/image_pool.py b/util/image_pool.py index 9f34a09..5a242e6 100644 --- a/util/image_pool.py +++ b/util/image_pool.py @@ -2,6 +2,8 @@ import random import numpy as np import torch from torch.autograd import Variable + + class ImagePool(): def __init__(self, pool_size): self.pool_size = pool_size diff --git a/util/visualizer.py b/util/visualizer.py index 02a36b7..22fe9da 100644 --- a/util/visualizer.py +++ b/util/visualizer.py @@ -4,7 +4,8 @@ import ntpath import time from . import util from . import html -from pdb import set_trace as st + + class Visualizer(): def __init__(self, opt): # self.opt = opt @@ -12,9 +13,10 @@ class Visualizer(): self.use_html = opt.isTrain and not opt.no_html self.win_size = opt.display_winsize self.name = opt.name + self.saved = False if self.display_id > 0: import visdom - self.vis = visdom.Visdom(port = opt.display_port) + self.vis = visdom.Visdom(port=opt.display_port) self.display_single_pane_ncols = opt.display_single_pane_ncols if self.use_html: @@ -27,15 +29,18 @@ class Visualizer(): now = time.strftime("%c") log_file.write('================ Training Loss (%s) ================\n' % now) + def reset(self): + self.saved = False + # |visuals|: dictionary of images to display or save - def display_current_results(self, visuals, epoch): - if self.display_id > 0: # show images in the browser + def display_current_results(self, visuals, epoch, save_result): + if self.display_id > 0: # show images in the browser if self.display_single_pane_ncols > 0: h, w = next(iter(visuals.values())).shape[:2] table_css = """""" % (w, h) + table {border-collapse: separate; border-spacing:4px; white-space:nowrap; text-align:center} + table td {width: %dpx; height: %dpx; padding: 4px; outline: 4px solid black} + """ % (w, h) ncols = self.display_single_pane_ncols title = self.name label_html = '' @@ -61,16 +66,17 @@ class Visualizer(): self.vis.images(images, nrow=ncols, win=self.display_id + 1, padding=2, opts=dict(title=title + ' images')) label_html = '%s
' % label_html - self.vis.text(table_css + label_html, win = self.display_id + 2, + self.vis.text(table_css + label_html, win=self.display_id + 2, opts=dict(title=title + ' labels')) else: idx = 1 for label, image_numpy in visuals.items(): - self.vis.image(image_numpy.transpose([2,0,1]), opts=dict(title=label), - win=self.display_id + idx) + self.vis.image(image_numpy.transpose([2, 0, 1]), opts=dict(title=label), + win=self.display_id + idx) idx += 1 - if self.use_html: # save images to a html file + if self.use_html and (save_result or not self.saved): # save images to a html file + self.saved = True for label, image_numpy in visuals.items(): img_path = os.path.join(self.img_dir, 'epoch%.3d_%s.png' % (epoch, label)) util.save_image(image_numpy, img_path) @@ -93,11 +99,11 @@ class Visualizer(): # errors: dictionary of error labels and values def plot_current_errors(self, epoch, counter_ratio, opt, errors): if not hasattr(self, 'plot_data'): - self.plot_data = {'X':[],'Y':[], 'legend':list(errors.keys())} + self.plot_data = {'X': [], 'Y': [], 'legend': list(errors.keys())} self.plot_data['X'].append(epoch + counter_ratio) self.plot_data['Y'].append([errors[k] for k in self.plot_data['legend']]) self.vis.line( - X=np.stack([np.array(self.plot_data['X'])]*len(self.plot_data['legend']),1), + X=np.stack([np.array(self.plot_data['X'])] * len(self.plot_data['legend']), 1), Y=np.array(self.plot_data['Y']), opts={ 'title': self.name + ' loss over time', -- cgit v1.2.3-70-g09d2 From 7a9021d4f131ee059d49ff9b2d135e6543f75763 Mon Sep 17 00:00:00 2001 From: junyanz Date: Sat, 4 Nov 2017 02:47:39 -0700 Subject: fix small issues --- models/pix2pix_model.py | 4 ++-- util/image_pool.py | 2 +- util/visualizer.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'models') diff --git a/models/pix2pix_model.py b/models/pix2pix_model.py index 8cd494f..388a8d3 100644 --- a/models/pix2pix_model.py +++ b/models/pix2pix_model.py @@ -86,14 +86,14 @@ class Pix2PixModel(BaseModel): def backward_D(self): # Fake # stop backprop to the generator by detaching fake_B - fake_AB = self.fake_AB_pool.query(torch.cat((self.real_A, self.fake_B), 1)) + fake_AB = self.fake_AB_pool.query(torch.cat((self.real_A, self.fake_B), 1).data) pred_fake = self.netD.forward(fake_AB.detach()) self.loss_D_fake = self.criterionGAN(pred_fake, False) # Real real_AB = torch.cat((self.real_A, self.real_B), 1) pred_real = self.netD.forward(real_AB) - self.loss_D_real = self.criterionGAN(self.pred_real, True) + self.loss_D_real = self.criterionGAN(pred_real, True) # Combined loss self.loss_D = (self.loss_D_fake + self.loss_D_real) * 0.5 diff --git a/util/image_pool.py b/util/image_pool.py index 5a242e6..ada1627 100644 --- a/util/image_pool.py +++ b/util/image_pool.py @@ -13,7 +13,7 @@ class ImagePool(): def query(self, images): if self.pool_size == 0: - return images + return Variable(images) return_images = [] for image in images: image = torch.unsqueeze(image, 0) diff --git a/util/visualizer.py b/util/visualizer.py index 22fe9da..e6e7cba 100644 --- a/util/visualizer.py +++ b/util/visualizer.py @@ -13,11 +13,11 @@ class Visualizer(): self.use_html = opt.isTrain and not opt.no_html self.win_size = opt.display_winsize self.name = opt.name + self.opt = opt self.saved = False if self.display_id > 0: import visdom self.vis = visdom.Visdom(port=opt.display_port) - self.display_single_pane_ncols = opt.display_single_pane_ncols if self.use_html: self.web_dir = os.path.join(opt.checkpoints_dir, opt.name, 'web') @@ -35,13 +35,13 @@ class Visualizer(): # |visuals|: dictionary of images to display or save def display_current_results(self, visuals, epoch, save_result): if self.display_id > 0: # show images in the browser - if self.display_single_pane_ncols > 0: + ncols = self.opt.display_single_pane_ncols + if ncols > 0: h, w = next(iter(visuals.values())).shape[:2] table_css = """""" % (w, h) - ncols = self.display_single_pane_ncols title = self.name label_html = '' label_html_row = '' @@ -76,7 +76,7 @@ class Visualizer(): idx += 1 if self.use_html and (save_result or not self.saved): # save images to a html file - self.saved = True + self.saved = True for label, image_numpy in visuals.items(): img_path = os.path.join(self.img_dir, 'epoch%.3d_%s.png' % (epoch, label)) util.save_image(image_numpy, img_path) -- cgit v1.2.3-70-g09d2 From a24e24d67d88f75869f447690f7d994fe7d42e2d Mon Sep 17 00:00:00 2001 From: junyanz Date: Sun, 5 Nov 2017 21:53:51 -0800 Subject: fix typo in the cyclegan --- models/cycle_gan_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'models') diff --git a/models/cycle_gan_model.py b/models/cycle_gan_model.py index 71a447d..e840e7b 100644 --- a/models/cycle_gan_model.py +++ b/models/cycle_gan_model.py @@ -98,7 +98,7 @@ class CycleGANModel(BaseModel): real_B = Variable(self.input_B, volatile=True) fake_A = self.netG_B.forward(real_B) self.rec_B = self.netG_A.forward(fake_A).data - self.fake_A = self.fake_A.data + self.fake_A = fake_A.data # get image paths def get_image_paths(self): -- cgit v1.2.3-70-g09d2 From c2fc8d442f1248231eab4b73e111665288b1e615 Mon Sep 17 00:00:00 2001 From: SsnL Date: Thu, 9 Nov 2017 16:08:30 -0500 Subject: update --- models/base_model.py | 2 +- models/cycle_gan_model.py | 30 ++++++++++++++---------------- models/networks.py | 4 ++-- models/pix2pix_model.py | 10 +++++----- models/test_model.py | 2 +- 5 files changed, 23 insertions(+), 25 deletions(-) (limited to 'models') diff --git a/models/base_model.py b/models/base_model.py index 646a014..9b55afe 100644 --- a/models/base_model.py +++ b/models/base_model.py @@ -44,7 +44,7 @@ class BaseModel(): save_path = os.path.join(self.save_dir, save_filename) torch.save(network.cpu().state_dict(), save_path) if len(gpu_ids) and torch.cuda.is_available(): - network.cuda(device_id=gpu_ids[0]) # network.cuda(device=gpu_ids[0]) for the latest version. + network.cuda(gpu_ids[0]) # helper loading function that can be used by subclasses def load_network(self, network, network_label, epoch_label): diff --git a/models/cycle_gan_model.py b/models/cycle_gan_model.py index e840e7b..fe06823 100644 --- a/models/cycle_gan_model.py +++ b/models/cycle_gan_model.py @@ -91,13 +91,13 @@ class CycleGANModel(BaseModel): def test(self): real_A = Variable(self.input_A, volatile=True) - fake_B = self.netG_A.forward(real_A) - self.rec_A = self.netG_B.forward(fake_B).data + fake_B = self.netG_A(real_A) + self.rec_A = self.netG_B(fake_B).data self.fake_B = fake_B.data real_B = Variable(self.input_B, volatile=True) - fake_A = self.netG_B.forward(real_B) - self.rec_B = self.netG_A.forward(fake_A).data + fake_A = self.netG_B(real_B) + self.rec_B = self.netG_A(fake_A).data self.fake_A = fake_A.data # get image paths @@ -106,10 +106,10 @@ class CycleGANModel(BaseModel): def backward_D_basic(self, netD, real, fake): # Real - pred_real = netD.forward(real) + pred_real = netD(real) loss_D_real = self.criterionGAN(pred_real, True) # Fake - pred_fake = netD.forward(fake.detach()) + pred_fake = netD(fake.detach()) loss_D_fake = self.criterionGAN(pred_fake, False) # Combined loss loss_D = (loss_D_real + loss_D_fake) * 0.5 @@ -134,17 +134,16 @@ class CycleGANModel(BaseModel): # Identity loss if lambda_idt > 0: # G_A should be identity if real_B is fed. - idt_A = self.netG_A.forward(self.real_B) + idt_A = self.netG_A(self.real_B) loss_idt_A = self.criterionIdt(idt_A, self.real_B) * lambda_B * lambda_idt # G_B should be identity if real_A is fed. - idt_B = self.netG_B.forward(self.real_A) + idt_B = self.netG_B(self.real_A) loss_idt_B = self.criterionIdt(idt_B, self.real_A) * lambda_A * lambda_idt self.idt_A = idt_A.data self.idt_B = idt_B.data self.loss_idt_A = loss_idt_A.data[0] self.loss_idt_B = loss_idt_B.data[0] - else: loss_idt_A = 0 loss_idt_B = 0 @@ -152,23 +151,22 @@ class CycleGANModel(BaseModel): self.loss_idt_B = 0 # GAN loss D_A(G_A(A)) - fake_B = self.netG_A.forward(self.real_A) - pred_fake = self.netD_A.forward(fake_B) + fake_B = self.netG_A(self.real_A) + pred_fake = self.netD_A(fake_B) loss_G_A = self.criterionGAN(pred_fake, True) # GAN loss D_B(G_B(B)) - fake_A = self.netG_B.forward(self.real_B) - pred_fake = self.netD_B.forward(fake_A) + fake_A = self.netG_B(self.real_B) + pred_fake = self.netD_B(fake_A) loss_G_B = self.criterionGAN(pred_fake, True) # Forward cycle loss - rec_A = self.netG_B.forward(fake_B) + rec_A = self.netG_B(fake_B) loss_cycle_A = self.criterionCycle(rec_A, self.real_A) * lambda_A # Backward cycle loss - rec_B = self.netG_A.forward(fake_A) + rec_B = self.netG_A(fake_A) loss_cycle_B = self.criterionCycle(rec_B, self.real_B) * lambda_B - # combined loss loss_G = loss_G_A + loss_G_B + loss_cycle_A + loss_cycle_B + loss_idt_A + loss_idt_B loss_G.backward() diff --git a/models/networks.py b/models/networks.py index d071ac4..ec6573b 100644 --- a/models/networks.py +++ b/models/networks.py @@ -118,7 +118,7 @@ def define_G(input_nc, output_nc, ngf, which_model_netG, norm='batch', use_dropo else: raise NotImplementedError('Generator model name [%s] is not recognized' % which_model_netG) if len(gpu_ids) > 0: - netG.cuda(device_id=gpu_ids[0]) # or netG.cuda(device=gpu_ids[0]) for latest version. + netG.cuda(gpu_ids[0]) init_weights(netG, init_type=init_type) return netG @@ -139,7 +139,7 @@ def define_D(input_nc, ndf, which_model_netD, raise NotImplementedError('Discriminator model name [%s] is not recognized' % which_model_netD) if use_gpu: - netD.cuda(device_id=gpu_ids[0]) # or netD.cuda(device=gpu_ids[0]) for latest version. + netD.cuda(gpu_ids[0]) init_weights(netD, init_type=init_type) return netD diff --git a/models/pix2pix_model.py b/models/pix2pix_model.py index 388a8d3..56adfc1 100644 --- a/models/pix2pix_model.py +++ b/models/pix2pix_model.py @@ -70,13 +70,13 @@ class Pix2PixModel(BaseModel): def forward(self): self.real_A = Variable(self.input_A) - self.fake_B = self.netG.forward(self.real_A) + self.fake_B = self.netG(self.real_A) self.real_B = Variable(self.input_B) # no backprop gradients def test(self): self.real_A = Variable(self.input_A, volatile=True) - self.fake_B = self.netG.forward(self.real_A) + self.fake_B = self.netG(self.real_A) self.real_B = Variable(self.input_B, volatile=True) # get image paths @@ -87,12 +87,12 @@ class Pix2PixModel(BaseModel): # Fake # stop backprop to the generator by detaching fake_B fake_AB = self.fake_AB_pool.query(torch.cat((self.real_A, self.fake_B), 1).data) - pred_fake = self.netD.forward(fake_AB.detach()) + pred_fake = self.netD(fake_AB.detach()) self.loss_D_fake = self.criterionGAN(pred_fake, False) # Real real_AB = torch.cat((self.real_A, self.real_B), 1) - pred_real = self.netD.forward(real_AB) + pred_real = self.netD(real_AB) self.loss_D_real = self.criterionGAN(pred_real, True) # Combined loss @@ -103,7 +103,7 @@ class Pix2PixModel(BaseModel): def backward_G(self): # First, G(A) should fake the discriminator fake_AB = torch.cat((self.real_A, self.fake_B), 1) - pred_fake = self.netD.forward(fake_AB) + pred_fake = self.netD(fake_AB) self.loss_G_GAN = self.criterionGAN(pred_fake, True) # Second, G(A) = B diff --git a/models/test_model.py b/models/test_model.py index 4af1fe1..2ae2812 100644 --- a/models/test_model.py +++ b/models/test_model.py @@ -34,7 +34,7 @@ class TestModel(BaseModel): def test(self): self.real_A = Variable(self.input_A) - self.fake_B = self.netG.forward(self.real_A) + self.fake_B = self.netG(self.real_A) # get image paths def get_image_paths(self): -- cgit v1.2.3-70-g09d2 From 1171d57b5db2d997a5ba3739e680af261f3a2e8a Mon Sep 17 00:00:00 2001 From: Taesung Park Date: Mon, 27 Nov 2017 22:05:28 -0800 Subject: fixed a bug in initialization of weights --- models/networks.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'models') diff --git a/models/networks.py b/models/networks.py index ec6573b..e6e0a87 100644 --- a/models/networks.py +++ b/models/networks.py @@ -14,11 +14,11 @@ def weights_init_normal(m): classname = m.__class__.__name__ # print(classname) if classname.find('Conv') != -1: - init.uniform(m.weight.data, 0.0, 0.02) + init.normal(m.weight.data, 0.0, 0.02) elif classname.find('Linear') != -1: - init.uniform(m.weight.data, 0.0, 0.02) + init.normal(m.weight.data, 0.0, 0.02) elif classname.find('BatchNorm2d') != -1: - init.uniform(m.weight.data, 1.0, 0.02) + init.normal(m.weight.data, 1.0, 0.02) init.constant(m.bias.data, 0.0) @@ -30,7 +30,7 @@ def weights_init_xavier(m): elif classname.find('Linear') != -1: init.xavier_normal(m.weight.data, gain=1) elif classname.find('BatchNorm2d') != -1: - init.uniform(m.weight.data, 1.0, 0.02) + init.normal(m.weight.data, 1.0, 0.02) init.constant(m.bias.data, 0.0) @@ -42,7 +42,7 @@ def weights_init_kaiming(m): elif classname.find('Linear') != -1: init.kaiming_normal(m.weight.data, a=0, mode='fan_in') elif classname.find('BatchNorm2d') != -1: - init.uniform(m.weight.data, 1.0, 0.02) + init.normal(m.weight.data, 1.0, 0.02) init.constant(m.bias.data, 0.0) @@ -54,7 +54,7 @@ def weights_init_orthogonal(m): elif classname.find('Linear') != -1: init.orthogonal(m.weight.data, gain=1) elif classname.find('BatchNorm2d') != -1: - init.uniform(m.weight.data, 1.0, 0.02) + init.normal(m.weight.data, 1.0, 0.02) init.constant(m.bias.data, 0.0) -- cgit v1.2.3-70-g09d2 From 7bda734dd7f3466d5d55afe80b97542b1b12bdb5 Mon Sep 17 00:00:00 2001 From: Taesung Park Date: Fri, 1 Dec 2017 22:13:51 -0800 Subject: changed the gain of xavier initialization from 1 to 0.02. implemented serial_batches option in unaligned dataset --- data/unaligned_dataset.py | 5 ++++- models/networks.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'models') diff --git a/data/unaligned_dataset.py b/data/unaligned_dataset.py index c5e5460..ad0c11b 100644 --- a/data/unaligned_dataset.py +++ b/data/unaligned_dataset.py @@ -25,7 +25,10 @@ class UnalignedDataset(BaseDataset): def __getitem__(self, index): A_path = self.A_paths[index % self.A_size] index_A = index % self.A_size - index_B = random.randint(0, self.B_size - 1) + if self.opt.serial_batches: + index_B = index % self.B_size + else: + index_B = random.randint(0, self.B_size - 1) B_path = self.B_paths[index_B] # print('(A, B) = (%d, %d)' % (index_A, index_B)) A_img = Image.open(A_path).convert('RGB') diff --git a/models/networks.py b/models/networks.py index e6e0a87..3c54138 100644 --- a/models/networks.py +++ b/models/networks.py @@ -26,9 +26,9 @@ def weights_init_xavier(m): classname = m.__class__.__name__ # print(classname) if classname.find('Conv') != -1: - init.xavier_normal(m.weight.data, gain=1) + init.xavier_normal(m.weight.data, gain=0.02) elif classname.find('Linear') != -1: - init.xavier_normal(m.weight.data, gain=1) + init.xavier_normal(m.weight.data, gain=0.02) elif classname.find('BatchNorm2d') != -1: init.normal(m.weight.data, 1.0, 0.02) init.constant(m.bias.data, 0.0) -- cgit v1.2.3-70-g09d2