0%

cycleGAN

这篇博客主要记录在跟随cycleGAN作者的代码复现学到的东西。
title: Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks(ICCV2017)

paper: https://arxiv.org/abs/1703.10593
code: https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix
mycode: https://github.com/TJJTJJTJJ/pytorch_cycleGAN
cycle_gan的整体框架写得很漂亮,frame可以参考github的frame

1.动态导入模块以及文件内的类

类似这种文件结构
.models
|— init.py
|— base_model.py
|— cycle_gan_model.py
|— networks.py
|— pix2pix_model.py
`— test_model.py

init.py这样写两个函数

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
def find_model_using_name(model_name):
"""
根据model_name导入具体模型'models/model_name_model.py'
:param model_name: eg. cycle_gan
:return: mdoel class eg.cycle_gan_model.CycleGANModle
"""
# step1 import 'models/model_name_model'
model_filename = 'models.'+model_name+'_model'
modellib = importlib.import_module(model_filename)

# step2 get model_name
model = None
target_model_name = model_name.replace('_','')+'model'
for name, cls in modellib.__dict__.items():
if name.lower() == target_model_name.lower() \
and issubclass(cls, BaseModel):
model = cls

if model is None:
print_str = "In {model_filename}.py, there should be a subclass of BaseModel with class name " \
"that matches {target_model_name} in lowercase.".format(model_filename=model_filename, \
target_model_name=target_model_name)
print(print_str)
exit(0)

return model
1
2
modellib.__dict__ == vars(modellib)
vars().keys() == dir()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import importlib
modellib = importlib.import_module(model_filename)

for k in dir(modellib):
print(k)
CycleGANModel
__builtins__
__cached__
__doc__
__file__
__loader__
__name__
__package__
__spec__

print(modellib.__dict__)
{'__name__': 'cycle_gan_model',
...
'CycleGANModel': cycle_gan_model.CycleGANModel}
1
2
exit(0)无错误退出
exit(1)有错误退出

2.学习率直线下降

1
2
3
4
5
6
for epoch in range(opt.epoch_count, opt.niter + opt.niter_decay + 1):

def lambda_rule(epoch):
lr_l = 1.0 - max(0, epoch + opt.epoch_count - opt.niter) / float(opt.niter_decay + 1)
return lr_l
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_rule)

3.NotImplemented && NotImplementedError

参考:
http://www.php.cn/python-tutorials-160083.html
https://stackoverflow.com/questions/1062096/python-notimplemented-constant

return NotImplemented
raise NotImplementedError(‘initialization method [%s] is not implemented’ % init_type)

4.parser的修改

这里既有外界传入的参数,也有自己的参数isTrain,在主函数里调用的时候调用方式是一致的,只是一个可以通过外界传参,一个不能通过外界传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TrainOptions():
def initialize(self):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument('--batch_size', type=int, default=1, help='input batch size')
parser.set_defaults(dataset_mode='single')
opt, _ = parser.parse_known_args()

self.isTrain = True
return opt
def parse(self):
opt = self.initialize()
opt.isTrain = self.isTrain

opt = TrainOptions().parse()

5.eval()和test()函数的结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def eval(self):
"""
make models eval mode during test time
:return: None
"""
for name in self.model_names:
if isinstance(name, str):
net = getattr(self, 'net'+name)
net.eval()

return None

def test(self):
"""
don't need backprop during test time
:return:
"""
with torch.no_grad():
self.forward()

model.eval()
model.test()

6.多GPU

结论

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
modelb = torch.nn.DataParallel(modela, device_ids=[0,1,2])
# save
torch.save(modelb.module.cpu().state_dict(),path)
modelb.cuda(gpu_ids[0])
# load
def load_networks(self, epoch):
for name in self.model_names:
if isinstance(name, str):
load_filename = '%s_net_%s.pth' % (epoch, name)
load_path = os.path.join(self.save_dir, load_filename)
net = getattr(self, 'net' + name)
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, map_location=str(self.device))
if hasattr(state_dict, '_metadata'):
del state_dict._metadata

# patch InstanceNorm checkpoints prior to 0.4
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)
# or
torch.nn.DataParallel加载预训练模型
import torch
class ModelA(torch.nn.Module):
def __init__(self):
super(ModelA, self).__init__()
self.base1 = torch.nn.Conv2d(2,2,2)
def forward(self,x):

pass
aa = ModelA()
bb = torch.nn.DataParallel(aa, device_ids=[0])
bb.module.load_state_dict(torch.load('aa.pth'))

对于单gpu和Module
对于普通的model.cuda,在保存模型会自动变成cpu,需要再次cuda一次
对于DataParallel,在保存模型会自动变成cpu,需要再次cuda一次
通过源码可以得知,DataParallel的device_ids初始化就已经确定,所以不用担心cuda到第一个GPU上而导致DataParallel忘记自己可以复制到哪些GPU上,会自动复制的

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
import torch
class ModelA(torch.nn.Module):
def __init__(self):
super(ModelA, self).__init__()
self.base = torch.nn.Conv2d(2,2,2,2)
def forward(self,x):
pass

aa = ModelA()
print(aa)
ModelA(
(base): Conv2d(2, 2, kernel_size=(2, 2), stride=(2, 2))
)
print(aa.state_dict())
OrderedDict([('base.weight', tensor([[[[ 0.0119, 0.2522],
[-0.0682, 0.2366]],

[[ 0.2013, 0.2106],
[ 0.2242, 0.1711]]],

[[[-0.2777, 0.2446],
[ 0.3494, 0.1552]],

[[ 0.0270, 0.1272],
[-0.1878, -0.3501]]]])), ('base.bias', tensor([ 0.1433, 0.1061]))])
aa.cuda()
print(aa.state_dict())
OrderedDict([('base.weight', tensor([[[[ 0.0119, 0.2522],
[-0.0682, 0.2366]],

[[ 0.2013, 0.2106],
[ 0.2242, 0.1711]]],

[[[-0.2777, 0.2446],
[ 0.3494, 0.1552]],

[[ 0.0270, 0.1272],
[-0.1878, -0.3501]]]], device='cuda:0')), ('base.bias', tensor([ 0.1433, 0.1061], device='cuda:0'))]

print(aa.cpu().state_dict())
OrderedDict([('base.weight', tensor([[[[ 0.1570, -0.2992],
[-0.2927, -0.2748]],
[[-0.0097, 0.0346],
[-0.3125, 0.2615]]],
[[[-0.2506, -0.2632],
[ 0.1302, -0.2223]],
[[ 0.1422, 0.0427],
[ 0.3453, 0.0219]]]])),
('base.bias', tensor([ 0.1974, -0.1549]))])

print(aa.state_dict())
OrderedDict([('base.weight', tensor([[[[ 0.1570, -0.2992],
[-0.2927, -0.2748]],

[[-0.0097, 0.0346],
[-0.3125, 0.2615]]],

[[[-0.2506, -0.2632],
[ 0.1302, -0.2223]],

[[ 0.1422, 0.0427],
[ 0.3453, 0.0219]]]])), ('base.bias', tensor([ 0.1974, -0.1549]))])

bb = torch.nn.DataParallel(aa, device_ids=[0])
print(bb)
DataParallel(
(module): ModelA(
(base): Conv2d(2, 2, kernel_size=(2, 2), stride=(2, 2))
)
)
print(bb.state_dict())
OrderedDict([('module.base.weight', tensor([[[[ 0.0119, 0.2522],
[-0.0682, 0.2366]],

[[ 0.2013, 0.2106],
[ 0.2242, 0.1711]]],

[[[-0.2777, 0.2446],
[ 0.3494, 0.1552]],

[[ 0.0270, 0.1272],
[-0.1878, -0.3501]]]], device='cuda:0')), ('module.base.bias', tensor([ 0.1433, 0.1061], device='cuda:0'))])
print(bb.module.cpu().state_dict())
OrderedDict([('base.weight', tensor([[[[ 0.1570, -0.2992],
[-0.2927, -0.2748]],
[[-0.0097, 0.0346],
[-0.3125, 0.2615]]],

[[[-0.2506, -0.2632],
[ 0.1302, -0.2223]],
[[ 0.1422, 0.0427],
[ 0.3453, 0.0219]]]])),
('base.bias', tensor([ 0.1974, -0.1549]))])
print(bb)
DataParallel(
(module): ModelA(
(base): Conv2d(2, 2, kernel_size=(2, 2), stride=(2, 2))
)
)
print(bb.state_dict())
OrderedDict([('base.weight', tensor([[[[ 0.0119, 0.2522],
[-0.0682, 0.2366]],

[[ 0.2013, 0.2106],
[ 0.2242, 0.1711]]],

[[[-0.2777, 0.2446],
[ 0.3494, 0.1552]],

[[ 0.0270, 0.1272],
[-0.1878, -0.3501]]]])), ('base.bias', tensor([ 0.1433, 0.1061]))])
bb.cuda(gpu_ids[0])
print(bb.state_dict())
OrderedDict([('module.base.weight', tensor([[[[ 0.0119, 0.2522],
[-0.0682, 0.2366]],

[[ 0.2013, 0.2106],
[ 0.2242, 0.1711]]],

[[[-0.2777, 0.2446],
[ 0.3494, 0.1552]],

[[ 0.0270, 0.1272],
[-0.1878, -0.3501]]]], device='cuda:0')), ('module.base.bias', tensor([ 0.1433, 0.1061], device='cuda:0'))])

7.Norm

参考:
https://blog.csdn.net/liuxiao214/article/details/81037416

输入图像:[N,C,H,W]
BatchNorm: [1,C,1,1]
InstanceNorm: [N,C,1,1]

经过实验,instanceNorm层的weight, bias, running_mean, running_var总是None
代码中加载模型的时候对instanceNorm层进行了删除操作,为什么
对于pytorch之前的版本instanceNorm层是有running_mean和running_var的,之后的版本修正了之后,就不再需要了

1
2
3
4
5
6
7
8
9
10
11
12
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)

8.functools

偏函数:适合为多个调用函数提供一致的函数接口

1
2
3
4
5
6
7
8
9
10
11
12
from functools import partial

def f(m,n,p):
return m*n*p
re=partial(f,3,4)
print(re(5)
# 60

if type(norm_layer) == functools.partial:
use_bias = norm_layer.func == nn.InstanceNorm2d
else:
use_bias = norm_layer == nn.InstanceNorm2d

9.论文与代码

ndf

模型的定义与论文有一个地方不一致,论文写的第一个conv之后通道数是32,但实现是64.
与作者沟通得知,第一层不是32,而是64,剩下的也依次递增.

下采样的时候没有使用reflect进行补充,而是使用了0填充.
与作者沟通后,提出的是都可以尝试一下

unet model

Unet model
与网上的不是很一致
3->1->2->4->8->8->8
3<-2<-4<-8<-16<-16<-16

参数 no_lsgan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
self.criterionGAN = networks.GANLoss(use_lsgan=not opt.no_lsgan).to(self.device)
# GAN loss
class GANLoss(nn.Module):
def __init__(self, use_lsgan=True, target_real_label=1.0, target_fake_label=0.0):
super(GANLoss, self).__init__()
self.register_buffer('real_label', torch.tensor(target_real_label))
self.register_buffer('fake_label', torch.tensor(target_fake_label))

if use_lsgan:
self.loss = nn.MSELoss()
else:
self.loss = nn.BCELoss()

use_sigmoid = opt.no_lsgan
self.netD_A = define_D(opt.output_nc, opt.ndf, opt.netD, opt.n_layers_D, opt.norm,
use_sigmoid, opt.init_type, opt.init_gain, self.gpu_ids)

也就是
opt.no_lsgan为True时, netD使用sigmoid, GANloss使用BCELoss()
opt.no_lsgan为False时, netD不使用sigmoid, GANloss使用MSELoss()

MSELoss:均方误差 (x-y)*2
BCELoss:二分类的交叉熵:使用前需要使用sigmoid函数,input和target的输入维度是一样的.(N,
)

根据作者提供的运行代码,猜测作者使用的是opt.no_lsgan为False,均方误差

L1loss: |x-y|

G and D 的反向传播过程

回顾一下G和D的反向传播
train G

1
2
3
4
5
6
set_requires_grad(D, False)
fake_A = G(real_A)
loss = criterion(D(fake_A), True)
optimizers_G.zero_grad()
loss.backward()
optimizers_G.step()

train D

1
2
3
4
5
6
7
8
set_requires_grad(D, False)
#fake_A = fake_A.detach() # 取消G的grad
loss1 = criterion(fake_A.detach(), False)
loss2 = criterion(realA, True)
loss = loss1 + loss2
optimizers_D.zero_grad()
loss.backward()
optimizers_D.step()

10.ConTransposed的计算方法

逆卷积后的图像大小和之前的能对应上,需要output_padding

1
2
3
4
nn.ConvTranspose2d(ngf*mult, int(ngf*mult/2), kernel_size=3,stride=2, padding=1, output_padding=1, bias=use_bias)]
-k+2p+s-out_padding是s的整数
k=3,s=2,p=1,则out_padding=1
k=3,s=4,p=1,则out_padding=3

11.初始化参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def init_weights(net, init_type='normal', gain=0.02):
def init_func(m):
# conv, contranspose ,linear, bn
# type(m) == nn.Conv2d
classname = m.__class__.__name__
if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
if init_type == 'normal':
init.normal_(m.weight.data, 0.0, gain)
elif init_type == 'xavier':
init.xavier_normal_(m.weight.data, gain=gain)
elif init_type == 'kaiming':
init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
elif init_type == 'orthogonal':
init.orthogonal_(m.weight.data, gain=gain)
else:
raise NotImplementedError('initialization method [%s] is not implemented' % init_type)
if hasattr(m, 'bias') and m.bias is not None:
init.constant_(m.bias.data, 0.0)
elif classname.find('BatchNorm2d') != -1:
init.normal_(m.weight.data, 1.0, gain)
init.constant_(m.bias.data, 0.0)

print('initialize network with %s' % init_type)
net.apply(init_func)

12.disriminator PatchGAN and GANLoss

PatchGAN的kernel是4.

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
class GANLoss(nn.Module):
def __init__(self, use_lsgan=True, target_real_label=1.0, target_fake_label=0.0):
super(GANLoss, self).__init__()
self.register_buffer('real_label', torch.tensor(target_real_label))
self.register_buffer('fake_label', torch.tensor(target_fake_label))
if use_lsgan:
self.loss = nn.MSELoss()
else:
self.loss = nn.BCELoss()

def get_target_tensor(self, input, target_is_real):
if target_is_real:
target_tensor = self.real_label
else:
target_tensor = self.fake_label
return target_tensor.expand_as(input)

def __call__(self, input, target_is_real):
target_tensor = self.get_target_tensor(input, target_is_real)
return self.loss(input, target_tensor)

# Defines the PatchGAN discriminator with the specified arguments.
class NLayerDiscriminator(nn.Module):
def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d, use_sigmoid=False):
super(NLayerDiscriminator, self).__init__()
if type(norm_layer) == functools.partial:
use_bias = norm_layer.func == nn.InstanceNorm2d
else:
use_bias = norm_layer == nn.InstanceNorm2d

kw = 4
padw = 1
sequence = [
nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw),
nn.LeakyReLU(0.2, True)
]

nf_mult = 1
nf_mult_prev = 1
for n in range(1, n_layers):
nf_mult_prev = nf_mult
nf_mult = min(2**n, 8)
sequence += [
nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
kernel_size=kw, stride=2, padding=padw, bias=use_bias),
norm_layer(ndf * nf_mult),
nn.LeakyReLU(0.2, True)
]

nf_mult_prev = nf_mult
nf_mult = min(2**n_layers, 8)
sequence += [
nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult,
kernel_size=kw, stride=1, padding=padw, bias=use_bias),
norm_layer(ndf * nf_mult),
nn.LeakyReLU(0.2, True)
]

sequence += [nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)]

if use_sigmoid:
sequence += [nn.Sigmoid()]

self.model = nn.Sequential(*sequence)

def forward(self, input):
return self.model(input)

pred_real = netD(real)
loss_D_real = self.criterionGAN(pred_real, True)

GANLoss的备注

使用时,直观上可将layer看成数学概念中的函数,调用layer(input)即可得到input对应的结果。它等价于layers.call(input),在call函数中,主要调用的是 layer.forward(x),另外还对钩子做了一些处理。所以在实际使用中应尽量使用layer(x)而不是使用layer.forward(x)。

13.PatchGAN的感受野

论文使用的是70X70 PatchGAN
PatchGAN:
paper:
Image-to-Image Translation with Conditional Adversarial Networks
https://arxiv.org/abs/1611.07004

自动计算网址:https://fomoro.com/tools/receptive-fields/

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
感受野的计算规则
对于第m层,m=0,1,2,...,N. hm表示第m层应该有的视野,假设mN=1
km, sm, pm,表示第m-1层到第m层的conv的kernel
第一层对于第0层的感受野
h1 = 1,
(h0-k1)/s1+1=h1
第二层对于第0层的感受野
h2 = 1
(h1-k2)/s2+1=h2
(h0-k1)/s1+1=h1
依次类推
def f(output_size, ksize, stride):
return (output_size - 1) * stride + ksize

last_layer = f(output_size=1, ksize=4, stride=1)
# Receptive field: 4
fourth_layer = f(output_size=last_layer, ksize=4, stride=1)
# Receptive field: 7
third_layer = f(output_size=fourth_layer, ksize=4, stride=2)
# Receptive field: 16
second_layer = f(output_size=third_layer, ksize=4, stride=2)
# Receptive field: 34
first_layer = f(output_size=second_layer, ksize=4, stride=2)
# Receptive field: 70

print(first_layer)

14.torch.tensor.clone()

clone()
梯度受影响,clone之后的新的tensor的梯度也会影响到原tensor,但是新tensor本身是没有梯度的.
clone之后的新tensor的改变不会影响原有的tensor
应该这么理解,clone也是计算图中的一个操作,这样的话就可以解释通了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import torch
input = torch.ones(3,3,3,3)
input.requires_grad = True
input2 = input.clone()
print(input2.requires_grad)
y = input.sum()
y.backward()
print(input.grad)
# 1,1,1...
print(input2.grad)
# None
y = input2.sum()
y.backward()
print(input.grad)
# 2,2,2...
print(input2.grad)
# None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import torch
input = torch.ones(3,3)
input.requires_grad = True
input2 = input.clone()
input2[1,1] = 6
print(input2)
print(input)
tensor([[ 2., 2., 2.],
[ 2., 6., 2.],
[ 2., 2., 2.]])
tensor([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])

input2[1,1] = 6
y = (input2*input2).sum()
y.backward()
print(input.grad)
print(input2.grad)
tensor([[ 8., 8., 8.],
[ 8., 4., 8.],
[ 8., 8., 8.]])
None

1
2
print(input2.grad_fn)
<CopySlices object at 0x7fe89dc841d0>

clone的用法
tensor保留梯度的交换

1
2
3
4
5
6
7
8
9
tmp = tensor1.clone()
tensor2 = tmp
tensor1 = tensor3
# or
tensor1, tensor2 = tensor3, tensor1.clone()
# or
tmp = self.images[random_id].clone()
self.images[random_id] = image
return_images.append(tmp)

15.from XX import

这里还有一些不太对的地方

1
2
3
4
5
from .base_model import BaseModel # 同一个文件夹
from util.image_pool import # 父级文件夹
# 建议
from .base_model import BaseModel # 同一个文件夹
from ..util.image_pool import # 父级文件夹

16.register_buffer

register_buffer
self.register_buffer可以将tensor注册成buffer,在forward中使用self.mybuffer, 而不是self.mybuffer_tmp.
定义Parameter和buffer都只需要传入Tensor即可。也不需要将其转成gpu。这是因为,当网络进行.cuda()时候,会自动将里面的层的参数,buffer等转换成相应的GPU上。
网络存储时也会将buffer存下,当网络load模型时,会将存储的模型的buffer也进行赋值。
buffer的更新在forward中,optim.step只能更新nn.Parameter类型的参数。
用法
self.register_buffer(‘running_mean’, torch.zeros(num_features))

17. itertools

无限迭代器
itertools,用于创建高效迭代器的函数,
itertools.chain 连接多个列表或者迭代器。
将多个网络写在一起,使用一个优化器

1
2
3
4
5
self.optimizer_G = torch.optim.Adam(itertools.chain(self.netG_A.parameters(), self.netG_B.parameters()),
lr=opt.lr, betas=(opt.beta1, 0.999))
self.optimizer_D = torch.optim.Adam(itertools.chain(self.netD_A.parameters(), self.netD_B.parameters()),
lr=opt.lr, betas=(opt.beta1, 0.999))

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
# 自然数无限迭代器
# itertools.count
>>> import itertools
>>> natuals = itertools.count(1)
>>> for n in natuals:
... print n
...
1
2
3
...

# 序列无限重复
>>> import itertools
>>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一种
>>> for c in cs:
... print c
...
'A'
'B'
'C'
'A'
'B'
'C'
...

# 单元素无限重复
>>> ns = itertools.repeat('A', 10)
>>> for n in ns:
... print n
...
打印10'A'

# 无限迭代器中截取有限序列
>>> natuals = itertools.count(1)
>>> ns = itertools.takewhile(lambda x: x <= 10, natuals)
>>> for n in ns:
... print n
...
打印出110

# 迭代对象的串联
for c in itertools.chain('ABC', 'XYZ'):
print c
# 迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z'

# 迭代器中相邻的重复元素挑出来放在一起
>>> for key, group in itertools.groupby('AAABBBCCAAA'):
... print key, list(group) # 为什么这里要用list()函数呢?
...
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']

# imap, ifilter
>>> for x in itertools.imap(lambda x, y: x * y, [10, 20, 30], itertools.count(1)):
... print x
...
10
40
90

18.visdom

1
2
3
self.vis = visdom.Visdom(server=opt.display_server, port=opt.display_port, 
env=opt.display_env, raise_exceptions=True, use_incoming_socket=False)
# env根据_自动分层。e.g. cycle_gan-->cycle,cycle_gan

19.三引号

1
2
3
4
5
6
7
8
9
10
三引号的作用
>>> str1 = """List of name:
... Hua Li
... Chao Deng
... {}
... """.format('hhh')
>>> print(str1)
List of name:
Hua Li
Chao Deng

20.异常

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
# 1.触发异常
def mye( level ):
if level < 1:
raise Exception("Invalid level!")
# 触发异常后,后面的代码就不会再执行
try:
mye(0) # 触发异常
except Exception as err:
print(1,err)
else:
print(2)

1 Invalid level!

# 2.自定义异常
class MyException(Exception):
def __init__(self,message):
Exception.__init__(self)
self.message=message
print('This is MyException')
a=7
if a<10:
try:
raise MyException("my excepition is raised ")
except MyException as e:
print('*****************')
print(e.message)
This is MyException
my excepition is raised

21.自定义类的iter

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
# 自定义类的iter
class cl1():
def __init__(self):
self.N = 10
def __iter__(self):
for i in range(10):
print(i)
if i < 5:
yield i
else:
break
cc = cl1()
for i in cc:
print('hhh',i)
0
hhh 0
1
hhh 1
2
hhh 2
3
hhh 3
4
hhh 4
5