srijaydeshpande commited on
Commit
e7610f7
·
verified ·
1 Parent(s): 06f17e8

Upload 28 files

Browse files
data/__init__.py ADDED
File without changes
data/aligned_dataset.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os.path
2
+ from data.base_dataset import BaseDataset, get_params, get_transform, normalize
3
+ from data.image_folder import make_dataset
4
+ from PIL import Image
5
+
6
+ class AlignedDataset(BaseDataset):
7
+ def initialize(self, opt):
8
+ self.opt = opt
9
+ self.root = opt.dataroot
10
+
11
+ ### input A (label maps)
12
+ dir_A = '_masks' if self.opt.label_nc == 0 else '_label'
13
+ self.dir_A = os.path.join(opt.dataroot, opt.phase + dir_A)
14
+ self.A_paths = sorted(make_dataset(self.dir_A))
15
+
16
+ ### input B (real images)
17
+ if opt.isTrain or opt.use_encoded_image:
18
+ self.A_paths = [path for path in self.A_paths if "pos_" in path] # neg for benign, pos for malignant
19
+ dir_B = '_images' if self.opt.label_nc == 0 else '_img'
20
+ self.dir_B = os.path.join(opt.dataroot, opt.phase + dir_B)
21
+ self.B_paths = sorted(make_dataset(self.dir_B))
22
+ self.B_paths = [path for path in self.B_paths if "pos_" in path] #neg for benign, pos for malignant
23
+
24
+ ### instance maps
25
+ if not opt.no_instance:
26
+ self.dir_inst = os.path.join(opt.dataroot, opt.phase + '_inst')
27
+ self.inst_paths = sorted(make_dataset(self.dir_inst))
28
+
29
+ ### load precomputed instance-wise encoded features
30
+ if opt.load_features:
31
+ self.dir_feat = os.path.join(opt.dataroot, opt.phase + '_feat')
32
+ print('----------- loading features from %s ----------' % self.dir_feat)
33
+ self.feat_paths = sorted(make_dataset(self.dir_feat))
34
+
35
+ self.dataset_size = len(self.A_paths)
36
+
37
+ def __getitem__(self, index):
38
+ ### input A (label maps)
39
+ A_path = self.A_paths[index]
40
+ A = Image.open(A_path)
41
+ params = get_params(self.opt, A.size)
42
+ if self.opt.label_nc == 0:
43
+ transform_A = get_transform(self.opt, params)
44
+ A_tensor = transform_A(A.convert('RGB'))
45
+ else:
46
+ transform_A = get_transform(self.opt, params, method=Image.NEAREST, normalize=False)
47
+ A_tensor = transform_A(A) * 255.0
48
+
49
+ B_tensor = inst_tensor = feat_tensor = 0
50
+ ### input B (real images)
51
+ if self.opt.isTrain or self.opt.use_encoded_image:
52
+ B_path = self.B_paths[index]
53
+ B = Image.open(B_path).convert('RGB')
54
+ transform_B = get_transform(self.opt, params)
55
+ B_tensor = transform_B(B)
56
+
57
+ ### if using instance maps
58
+ if not self.opt.no_instance:
59
+ inst_path = self.inst_paths[index]
60
+ inst = Image.open(inst_path)
61
+ inst_tensor = transform_A(inst)
62
+
63
+ if self.opt.load_features:
64
+ feat_path = self.feat_paths[index]
65
+ feat = Image.open(feat_path).convert('RGB')
66
+ norm = normalize()
67
+ feat_tensor = norm(transform_A(feat))
68
+
69
+ input_dict = {'label': A_tensor, 'inst': inst_tensor, 'image': B_tensor,
70
+ 'feat': feat_tensor, 'path': A_path}
71
+
72
+ return input_dict
73
+
74
+ def __len__(self):
75
+ return len(self.A_paths) // self.opt.batchSize * self.opt.batchSize
76
+
77
+ def name(self):
78
+ return 'AlignedDataset'
data/base_data_loader.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ class BaseDataLoader():
3
+ def __init__(self):
4
+ pass
5
+
6
+ def initialize(self, opt):
7
+ self.opt = opt
8
+ pass
9
+
10
+ def load_data():
11
+ return None
12
+
13
+
14
+
data/base_dataset.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.utils.data as data
2
+ from PIL import Image
3
+ import torchvision.transforms as transforms
4
+ import numpy as np
5
+ import random
6
+
7
+ class BaseDataset(data.Dataset):
8
+ def __init__(self):
9
+ super(BaseDataset, self).__init__()
10
+
11
+ def name(self):
12
+ return 'BaseDataset'
13
+
14
+ def initialize(self, opt):
15
+ pass
16
+
17
+ def get_params(opt, size):
18
+ w, h = size
19
+ new_h = h
20
+ new_w = w
21
+ if opt.resize_or_crop == 'resize_and_crop':
22
+ new_h = new_w = opt.loadSize
23
+ elif opt.resize_or_crop == 'scale_width_and_crop':
24
+ new_w = opt.loadSize
25
+ new_h = opt.loadSize * h // w
26
+
27
+ x = random.randint(0, np.maximum(0, new_w - opt.fineSize))
28
+ y = random.randint(0, np.maximum(0, new_h - opt.fineSize))
29
+
30
+ flip = random.random() > 0.5
31
+ return {'crop_pos': (x, y), 'flip': flip}
32
+
33
+ def get_transform(opt, params, method=Image.BICUBIC, normalize=True):
34
+ transform_list = []
35
+ if 'resize' in opt.resize_or_crop:
36
+ osize = [opt.loadSize, opt.loadSize]
37
+ transform_list.append(transforms.Scale(osize, method))
38
+ elif 'scale_width' in opt.resize_or_crop:
39
+ transform_list.append(transforms.Lambda(lambda img: __scale_width(img, opt.loadSize, method)))
40
+
41
+ if 'crop' in opt.resize_or_crop:
42
+ transform_list.append(transforms.Lambda(lambda img: __crop(img, params['crop_pos'], opt.fineSize)))
43
+
44
+ if opt.resize_or_crop == 'none':
45
+ base = float(2 ** opt.n_downsample_global)
46
+ if opt.netG == 'local':
47
+ base *= (2 ** opt.n_local_enhancers)
48
+ transform_list.append(transforms.Lambda(lambda img: __make_power_2(img, base, method)))
49
+
50
+ if opt.isTrain and not opt.no_flip:
51
+ transform_list.append(transforms.Lambda(lambda img: __flip(img, params['flip'])))
52
+
53
+ transform_list += [transforms.ToTensor()]
54
+
55
+ if normalize:
56
+ transform_list += [transforms.Normalize((0.5, 0.5, 0.5),
57
+ (0.5, 0.5, 0.5))]
58
+ return transforms.Compose(transform_list)
59
+
60
+ def normalize():
61
+ return transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
62
+
63
+ def __make_power_2(img, base, method=Image.BICUBIC):
64
+ ow, oh = img.size
65
+ h = int(round(oh / base) * base)
66
+ w = int(round(ow / base) * base)
67
+ if (h == oh) and (w == ow):
68
+ return img
69
+ return img.resize((w, h), method)
70
+
71
+ def __scale_width(img, target_width, method=Image.BICUBIC):
72
+ ow, oh = img.size
73
+ if (ow == target_width):
74
+ return img
75
+ w = target_width
76
+ h = int(target_width * oh / ow)
77
+ return img.resize((w, h), method)
78
+
79
+ def __crop(img, pos, size):
80
+ ow, oh = img.size
81
+ x1, y1 = pos
82
+ tw = th = size
83
+ if (ow > tw or oh > th):
84
+ return img.crop((x1, y1, x1 + tw, y1 + th))
85
+ return img
86
+
87
+ def __flip(img, flip):
88
+ if flip:
89
+ return img.transpose(Image.FLIP_LEFT_RIGHT)
90
+ return img
data/custom_dataset_data_loader.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch.utils.data
2
+ from data.base_data_loader import BaseDataLoader
3
+
4
+
5
+ def CreateDataset(opt):
6
+ dataset = None
7
+ from data.aligned_dataset import AlignedDataset
8
+ dataset = AlignedDataset()
9
+
10
+ print("dataset [%s] was created" % (dataset.name()))
11
+ dataset.initialize(opt)
12
+ return dataset
13
+
14
+ class CustomDatasetDataLoader(BaseDataLoader):
15
+ def name(self):
16
+ return 'CustomDatasetDataLoader'
17
+
18
+ def initialize(self, opt):
19
+ BaseDataLoader.initialize(self, opt)
20
+ self.dataset = CreateDataset(opt)
21
+ self.dataloader = torch.utils.data.DataLoader(
22
+ self.dataset,
23
+ batch_size=opt.batchSize,
24
+ shuffle=not opt.serial_batches,
25
+ num_workers=int(opt.nThreads))
26
+
27
+ def load_data(self):
28
+ return self.dataloader
29
+
30
+ def __len__(self):
31
+ return min(len(self.dataset), self.opt.max_dataset_size)
data/data_loader.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+
2
+ def CreateDataLoader(opt):
3
+ from data.custom_dataset_data_loader import CustomDatasetDataLoader
4
+ data_loader = CustomDatasetDataLoader()
5
+ print(data_loader.name())
6
+ data_loader.initialize(opt)
7
+ return data_loader
data/image_folder.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ###############################################################################
2
+ # Code from
3
+ # https://github.com/pytorch/vision/blob/master/torchvision/datasets/folder.py
4
+ # Modified the original code so that it also loads images from the current
5
+ # directory as well as the subdirectories
6
+ ###############################################################################
7
+ import torch.utils.data as data
8
+ from PIL import Image
9
+ import os
10
+
11
+ IMG_EXTENSIONS = [
12
+ '.jpg', '.JPG', '.jpeg', '.JPEG',
13
+ '.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP', '.tiff'
14
+ ]
15
+
16
+
17
+ def is_image_file(filename):
18
+ return any(filename.endswith(extension) for extension in IMG_EXTENSIONS)
19
+
20
+
21
+ def make_dataset(dir):
22
+ images = []
23
+ assert os.path.isdir(dir), '%s is not a valid directory' % dir
24
+
25
+ for root, _, fnames in sorted(os.walk(dir)):
26
+ for fname in fnames:
27
+ if is_image_file(fname):
28
+ path = os.path.join(root, fname)
29
+ images.append(path)
30
+
31
+ return images
32
+
33
+
34
+ def default_loader(path):
35
+ return Image.open(path).convert('RGB')
36
+
37
+
38
+ class ImageFolder(data.Dataset):
39
+
40
+ def __init__(self, root, transform=None, return_paths=False,
41
+ loader=default_loader):
42
+ imgs = make_dataset(root)
43
+ if len(imgs) == 0:
44
+ raise(RuntimeError("Found 0 images in: " + root + "\n"
45
+ "Supported image extensions are: " +
46
+ ",".join(IMG_EXTENSIONS)))
47
+
48
+ self.root = root
49
+ self.imgs = imgs
50
+ self.transform = transform
51
+ self.return_paths = return_paths
52
+ self.loader = loader
53
+
54
+ def __getitem__(self, index):
55
+ path = self.imgs[index]
56
+ img = self.loader(path)
57
+ if self.transform is not None:
58
+ img = self.transform(img)
59
+ if self.return_paths:
60
+ return img, path
61
+ else:
62
+ return img
63
+
64
+ def __len__(self):
65
+ return len(self.imgs)
diffusion.py ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import matplotlib.pyplot as plt
3
+ from torchvision.utils import save_image
4
+ from torchvision import transforms
5
+ from vqvae_data.latents import LatentsDataset
6
+ from torch.utils.data import DataLoader
7
+ import numpy as np, os
8
+ from torch import nn
9
+ import math
10
+ import torch.nn.functional as F
11
+ from torch.optim import Adam
12
+ from typing import Optional
13
+ import random
14
+
15
+
16
+ def mkdir(dir):
17
+ if not os.path.exists(dir):
18
+ os.makedirs(dir)
19
+
20
+
21
+ def get_beta_schedule(beta_schedule, beta_start, beta_end, num_diffusion_timesteps):
22
+ def sigmoid(x):
23
+ return 1 / (np.exp(-x) + 1)
24
+
25
+ if beta_schedule == "quad":
26
+ betas = (
27
+ np.linspace(
28
+ beta_start ** 0.5,
29
+ beta_end ** 0.5,
30
+ num_diffusion_timesteps,
31
+ dtype=np.float64,
32
+ )
33
+ ** 2
34
+ )
35
+
36
+ elif beta_schedule == "linear":
37
+ betas = np.linspace(
38
+ beta_start, beta_end, num_diffusion_timesteps, dtype=np.float64
39
+ )
40
+ elif beta_schedule == "const":
41
+ betas = beta_end * np.ones(num_diffusion_timesteps, dtype=np.float64)
42
+ elif beta_schedule == "jsd": # 1/T, 1/(T-1), 1/(T-2), ..., 1
43
+ betas = 1.0 / np.linspace(
44
+ num_diffusion_timesteps, 1, num_diffusion_timesteps, dtype=np.float64
45
+ )
46
+ elif beta_schedule == "sigmoid":
47
+ betas = np.linspace(-6, 6, num_diffusion_timesteps)
48
+ betas = sigmoid(betas) * (beta_end - beta_start) + beta_start
49
+ else:
50
+ raise NotImplementedError(beta_schedule)
51
+ assert betas.shape == (num_diffusion_timesteps,)
52
+ betas = torch.from_numpy(betas).float()
53
+ return betas
54
+
55
+
56
+ def get_index_from_list(vals, t, x_shape):
57
+ """
58
+ Returns a specific index t of a passed list of values vals
59
+ while considering the batch dimension.
60
+ """
61
+ batch_size = t.shape[0]
62
+ out = vals.gather(-1, t.cpu())
63
+ return out.reshape(batch_size, *((1,) * (len(x_shape) - 1))).to(t.device)
64
+
65
+
66
+ def forward_diffusion_sample(x, t, device="cpu"):
67
+ """
68
+ Takes an image and a timestep as input and
69
+ returns the noisy version of it
70
+ """
71
+ noise = torch.randn_like(x) # gaussian noise
72
+ # noise = torch.FloatTensor(x.shape).uniform_(-1, 1) #uniform distribution noise
73
+ sqrt_alphas_cumprod_t = get_index_from_list(sqrt_alphas_cumprod, t, x.shape)
74
+ sqrt_one_minus_alphas_cumprod_t = get_index_from_list(
75
+ sqrt_one_minus_alphas_cumprod, t, x.shape
76
+ )
77
+ # print("coeff stats ",sqrt_alphas_cumprod_t, " and ", sqrt_one_minus_alphas_cumprod_t)
78
+ # mean + variance
79
+ return sqrt_alphas_cumprod_t.to(device) * x.to(device) \
80
+ + sqrt_one_minus_alphas_cumprod_t.to(device) * noise.to(device), noise.to(device)
81
+
82
+
83
+ class Block(nn.Module):
84
+ def __init__(self, in_ch, out_ch, time_emb_dim, up=False):
85
+ super().__init__()
86
+ self.time_mlp = nn.Linear(time_emb_dim, out_ch)
87
+ if up:
88
+ self.conv1 = nn.Conv2d(2 * in_ch, out_ch, 3, padding=1)
89
+ self.transform = nn.ConvTranspose2d(out_ch, out_ch, 4, 2, 1)
90
+ else:
91
+ self.conv1 = nn.Conv2d(in_ch, out_ch, 3, padding=1)
92
+ self.transform = nn.Conv2d(out_ch, out_ch, 4, 2, 1)
93
+ self.conv2 = nn.Conv2d(out_ch, out_ch, 3, padding=1)
94
+ self.bnorm1 = nn.BatchNorm2d(out_ch)
95
+ self.bnorm2 = nn.BatchNorm2d(out_ch)
96
+ self.relu = nn.LeakyReLU(0.2)
97
+
98
+ def forward(self, x, t, ):
99
+ # First Conv
100
+ h = self.bnorm1(self.relu(self.conv1(x)))
101
+ # Time embedding
102
+ time_emb = self.relu(self.time_mlp(t))
103
+ # Extend last 2 dimensions
104
+ time_emb = time_emb[(...,) + (None,) * 2]
105
+ # Add time channel
106
+ h = h + time_emb
107
+ # Second Conv
108
+ h = self.bnorm2(self.relu(self.conv2(h)))
109
+ # Down or Upsample
110
+ return self.transform(h)
111
+
112
+
113
+ class SinusoidalPositionEmbeddings(nn.Module):
114
+ def __init__(self, dim):
115
+ super().__init__()
116
+ self.dim = dim
117
+
118
+ def forward(self, time):
119
+ device = time.device
120
+ half_dim = self.dim // 2
121
+ embeddings = math.log(10000) / (half_dim - 1)
122
+ embeddings = torch.exp(torch.arange(half_dim, device=device) * -embeddings)
123
+ embeddings = time[:, None] * embeddings[None, :]
124
+ embeddings = torch.cat((embeddings.sin(), embeddings.cos()), dim=-1)
125
+ return embeddings
126
+
127
+
128
+ class CrossAttention(nn.Module):
129
+ """
130
+ ### Cross Attention Layer
131
+ This falls-back to self-attention when conditional embeddings are not specified.
132
+ """
133
+
134
+ use_flash_attention: bool = True
135
+
136
+ def __init__(self, d_model: int, d_cond: int, n_heads: int, d_head: int, is_inplace: bool = False):
137
+ """
138
+ :param d_model: is the input embedding size
139
+ :param n_heads: is the number of attention heads
140
+ :param d_head: is the size of a attention head
141
+ :param d_cond: is the size of the conditional embeddings
142
+ :param is_inplace: specifies whether to perform the attention softmax computation inplace to
143
+ save memory
144
+ """
145
+ super().__init__()
146
+
147
+ self.is_inplace = is_inplace
148
+ self.n_heads = n_heads
149
+ self.d_head = d_head
150
+
151
+ # Attention scaling factor
152
+ self.scale = d_head ** -0.5
153
+
154
+ # Query, key and value mappings
155
+ d_attn = d_head * n_heads
156
+ self.to_q = nn.Linear(d_model, d_attn, bias=False)
157
+ self.to_k = nn.Linear(d_cond, d_attn, bias=False)
158
+ self.to_v = nn.Linear(d_cond, d_attn, bias=False)
159
+
160
+ # Final linear layer
161
+ self.to_out = nn.Sequential(nn.Linear(d_attn, d_model))
162
+
163
+ def forward(self, x: torch.Tensor, cond: Optional[torch.Tensor] = None):
164
+ """
165
+ :param x: are the input embeddings of shape `[batch_size, height * width, d_model]`
166
+ :param cond: is the conditional embeddings of shape `[batch_size, n_cond, d_cond]`
167
+ """
168
+
169
+ # If `cond` is `None` we perform self attention
170
+ has_cond = cond is not None
171
+ if not has_cond:
172
+ cond = x
173
+
174
+ # Get query, key and value vectors
175
+ q = self.to_q(x)
176
+ k = self.to_k(cond)
177
+ v = self.to_v(cond)
178
+
179
+ return self.normal_attention(q, k, v)
180
+
181
+ def normal_attention(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor):
182
+ """
183
+ #### Normal Attention
184
+
185
+ :param q: are the query vectors before splitting heads, of shape `[batch_size, seq, d_attn]`
186
+ :param k: are the query vectors before splitting heads, of shape `[batch_size, seq, d_attn]`
187
+ :param v: are the query vectors before splitting heads, of shape `[batch_size, seq, d_attn]`
188
+ """
189
+
190
+ # Split them to heads of shape `[batch_size, seq_len, n_heads, d_head]`
191
+ q = q.view(*q.shape[:2], self.n_heads, -1)
192
+ k = k.view(*k.shape[:2], self.n_heads, -1)
193
+ v = v.view(*v.shape[:2], self.n_heads, -1)
194
+
195
+ # Calculate attention $\frac{Q K^\top}{\sqrt{d_{key}}}$
196
+ attn = torch.einsum('bihd,bjhd->bhij', q, k) * self.scale
197
+
198
+ # Compute softmax
199
+ # $$\underset{seq}{softmax}\Bigg(\frac{Q K^\top}{\sqrt{d_{key}}}\Bigg)$$
200
+ if self.is_inplace:
201
+ half = attn.shape[0] // 2
202
+ attn[half:] = attn[half:].softmax(dim=-1)
203
+ attn[:half] = attn[:half].softmax(dim=-1)
204
+ else:
205
+ attn = attn.softmax(dim=-1)
206
+
207
+ # Compute attention output
208
+ # $$\underset{seq}{softmax}\Bigg(\frac{Q K^\top}{\sqrt{d_{key}}}\Bigg)V$$
209
+ out = torch.einsum('bhij,bjhd->bihd', attn, v)
210
+ # Reshape to `[batch_size, height * width, n_heads * d_head]`
211
+ out = out.reshape(*out.shape[:2], -1)
212
+ # Map to `[batch_size, height * width, d_model]` with a linear layer
213
+ return self.to_out(out)
214
+
215
+
216
+ class SimpleUnet(nn.Module):
217
+ def __init__(self):
218
+ super().__init__()
219
+ image_channels = 3
220
+ # down_channels = (64, 128, 256, 512, 1024)
221
+ # up_channels = (1024, 512, 256, 128, 64)
222
+ down_channels = (16, 32, 64, 128, 256)
223
+ up_channels = (256, 128, 64, 32, 16)
224
+ out_dim = 1
225
+ time_emb_dim = 32
226
+
227
+ # Time embedding
228
+ self.time_mlp = nn.Sequential(
229
+ SinusoidalPositionEmbeddings(time_emb_dim),
230
+ nn.Linear(time_emb_dim, time_emb_dim),
231
+ nn.ReLU()
232
+ )
233
+
234
+ # Initial projection
235
+ self.conv0 = nn.Conv2d(image_channels, down_channels[0], 3, padding=1)
236
+
237
+ # Downsample
238
+ self.downs = nn.ModuleList([Block(down_channels[i], down_channels[i + 1], \
239
+ time_emb_dim) \
240
+ for i in range(len(down_channels) - 1)])
241
+ # Upsample
242
+ self.ups = nn.ModuleList([Block(up_channels[i], up_channels[i + 1], \
243
+ time_emb_dim, up=True) \
244
+ for i in range(len(up_channels) - 1)])
245
+
246
+ self.silu = nn.SiLU()
247
+
248
+ self.output = nn.Conv2d(up_channels[-1], 3, out_dim)
249
+
250
+ self.apply_tanh = nn.Tanh()
251
+
252
+ self.cross_attention_module = CrossAttention(3, 32, 16, 16)
253
+
254
+ def forward(self, x, y, timestep):
255
+
256
+ # Embedd class condition using cross attention
257
+ batch_size = x.shape[0]
258
+ y = self.time_mlp(y)
259
+ y = y[:, None, :]
260
+ x = x.permute(0, 2, 3, 1).view(batch_size, IMG_SIZE * IMG_SIZE, 3)
261
+ x2 = x + self.cross_attention_module(x, y)
262
+ x2 = x2.view(batch_size, IMG_SIZE, IMG_SIZE, 3).permute(0, 3, 1, 2)
263
+
264
+ # Embedd time
265
+ t = self.time_mlp(timestep)
266
+
267
+ # Initial conv
268
+ x2 = self.conv0(x2)
269
+
270
+ # Unet
271
+ residual_inputs = []
272
+ for down in self.downs:
273
+ x2 = down(x2, t)
274
+ residual_inputs.append(x2)
275
+ for up in self.ups:
276
+ residual_x2 = residual_inputs.pop()
277
+ # Add residual x2 as additional channels
278
+ x2 = torch.cat((x2, residual_x2), dim=1)
279
+ x2 = up(x2, t)
280
+
281
+ x2 = self.silu(x2)
282
+
283
+ output = self.output(x2)
284
+
285
+ return output
286
+
287
+
288
+ def get_loss(model, x_0, t):
289
+ latent, condition = x_0 # both latents and condition have same shap
290
+ latent = latent.cuda()
291
+ condition = condition.cuda()
292
+ x_noisy, noise = forward_diffusion_sample(latent, t, device)
293
+ noise_pred = model(x_noisy, condition, t)
294
+
295
+ # return F.l1_loss(noise, noise_pred)
296
+ return F.mse_loss(noise, noise_pred)
297
+
298
+
299
+ @torch.no_grad()
300
+ def sample_timestep(x, model, y, t):
301
+ betas_t = get_index_from_list(betas, t, x.shape)
302
+ sqrt_one_minus_alphas_cumprod_t = get_index_from_list(
303
+ sqrt_one_minus_alphas_cumprod, t, x.shape
304
+ )
305
+ sqrt_recip_alphas_t = get_index_from_list(sqrt_recip_alphas, t, x.shape)
306
+
307
+ # Call model (current image - noise prediction)
308
+ model_mean = sqrt_recip_alphas_t * (
309
+ x - (betas_t / sqrt_one_minus_alphas_cumprod_t) * model(x, y, t)
310
+ )
311
+ posterior_variance_t = get_index_from_list(posterior_variance, t, x.shape)
312
+
313
+ # print("model prediction stats ",torch.max(model(x, y, t)), " and ", torch.min(model(x, y, t)))
314
+
315
+ if t == 0:
316
+ return model_mean
317
+ else:
318
+ noise = torch.randn_like(x)
319
+ return model_mean + torch.sqrt(posterior_variance_t) * noise
320
+
321
+
322
+ def show_tensor_image(image):
323
+ reverse_transforms = transforms.Compose([
324
+ transforms.Lambda(lambda t: (t + 1) / 2),
325
+ transforms.Lambda(lambda t: t.permute(1, 2, 0)), # CHW to HWC
326
+ transforms.Lambda(lambda t: t * 255.),
327
+ transforms.Lambda(lambda t: t.numpy().astype(np.uint8)),
328
+ transforms.ToPILImage(),
329
+ ])
330
+
331
+ # Take first image of batch
332
+ if len(image.shape) == 4:
333
+ image = image[0, :, :, :]
334
+ plt.imshow(reverse_transforms(image))
335
+
336
+
337
+ def generate_latent(model_dir, cancer_type, output_dir):
338
+ if (cancer_type == 'benign'):
339
+ model_name = "digestpath_mask_benign_default.pt"
340
+ else:
341
+ model_name = "digestpath_mask_malignant_default.pt"
342
+
343
+ device = "cuda" if torch.cuda.is_available() else "cpu"
344
+
345
+
346
+ model_path = os.path.join(model_dir, model_name)
347
+
348
+ model = SimpleUnet()
349
+ model.to(device)
350
+
351
+ model.load_state_dict(torch.load(model_path))
352
+ print("model loaded")
353
+ model.eval()
354
+
355
+ # cancer_grade = random.randint(0, 1)
356
+ condition = torch.tensor([1]).cuda() # benign:0/malignant:1 grade cancer
357
+ # condition = torch.full([1, 1, IMG_SIZE, IMG_SIZE], condition).float().cuda()
358
+ img = torch.randn((1, 3, IMG_SIZE, IMG_SIZE), device=device)
359
+ for j in range(0, T)[::-1]:
360
+ t = torch.full((1,), j, device=device, dtype=torch.long)
361
+ img = sample_timestep(img, model, condition, t)
362
+ print("sampled image ", torch.max(img), " and ", torch.min(img))
363
+ save_image(img, os.path.join(output_dir, "sample.png"))
364
+ torch.save(img, os.path.join(output_dir, "sample.pt"))
365
+
366
+ # Define beta schedule
367
+ T = 1000
368
+ IMG_SIZE = 64
369
+
370
+ betas = get_beta_schedule(beta_schedule="linear",
371
+ beta_start=0.0001,
372
+ beta_end=0.02,
373
+ num_diffusion_timesteps=T)
374
+
375
+ # Pre-calculate different terms for closed form
376
+ alphas = 1. - betas
377
+ alphas_cumprod = torch.cumprod(alphas, axis=0)
378
+ sqrt_alphas_cumprod = torch.sqrt(alphas_cumprod) # root(alpha_bar)
379
+ sqrt_one_minus_alphas_cumprod = torch.sqrt(1. - alphas_cumprod) # root(1-alpha_bar)
380
+ sqrt_recip_alphas = torch.sqrt(1.0 / alphas) # 1/root(alpha)
381
+ alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (1, 0), value=1.0)
382
+ posterior_variance = betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod)
383
+
384
+
385
+ # model_dir = "trained_models/diffusion"
386
+ # output_dir = r"F:\Datasets\DigestPath\scene_generation\all\1000\256\test\output\benign"
387
+ # generate_latent(model_dir, 'malignant', output_dir)
interface.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ import argparse
4
+ import shutil
5
+ from PIL import Image
6
+ import PIL
7
+ import gradio as gr
8
+ import random
9
+ import numpy as np
10
+ from diffusion import generate_latent
11
+ from vq_vae import create_mask
12
+
13
+ model_dir = 'trained_models'
14
+
15
+ def create_image(cancer_type):
16
+ tmp_dir = "./tmp"
17
+ if os.path.exists(tmp_dir):
18
+ shutil.rmtree(tmp_dir)
19
+ os.makedirs(tmp_dir)
20
+ generate_latent(model_dir, cancer_type, tmp_dir)
21
+ create_mask(model_dir, "./tmp", "./tmp/test_masks")
22
+ os.system('python pix2pixhd_test.py --name diffusion_dp --dataroot ./tmp --label_nc 0 --no_instance --resize_or_crop none')
23
+ image_dir = "./tmp/diffusion_dp/test_latest/images"
24
+ input_label_image = Image.open(os.path.join(image_dir, "sample_input_label.jpg"))
25
+ synthesized_image = Image.open(os.path.join(image_dir, "sample_synthesized_image.jpg"))
26
+ return input_label_image, synthesized_image
27
+
28
+
29
+ demo = gr.Interface(
30
+ create_image,
31
+ inputs=gr.Radio(choices=["benign", "malignant"], label="Choose Type", value="benign"),
32
+ outputs=[gr.Image(), gr.Image()],
33
+ title="Diffusion based Image Generation"
34
+ )
35
+
36
+ demo.launch()
37
+
38
+ # create_image('benign')
models/__init__.py ADDED
File without changes
models/base_model.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ import sys
4
+
5
+ class BaseModel(torch.nn.Module):
6
+ def name(self):
7
+ return 'BaseModel'
8
+
9
+ def initialize(self, opt):
10
+ self.opt = opt
11
+ self.gpu_ids = opt.gpu_ids
12
+ self.isTrain = opt.isTrain
13
+ self.Tensor = torch.cuda.FloatTensor if self.gpu_ids else torch.Tensor
14
+ self.save_dir = os.path.join(opt.checkpoints_dir, opt.name)
15
+
16
+ def set_input(self, input):
17
+ self.input = input
18
+
19
+ def forward(self):
20
+ pass
21
+
22
+ # used in test time, no backprop
23
+ def test(self):
24
+ pass
25
+
26
+ def get_image_paths(self):
27
+ pass
28
+
29
+ def optimize_parameters(self):
30
+ pass
31
+
32
+ def get_current_visuals(self):
33
+ return self.input
34
+
35
+ def get_current_errors(self):
36
+ return {}
37
+
38
+ def save(self, label):
39
+ pass
40
+
41
+ # helper saving function that can be used by subclasses
42
+ def save_network(self, network, network_label, epoch_label, gpu_ids):
43
+ save_filename = '%s_net_%s.pth' % (epoch_label, network_label)
44
+ save_path = os.path.join(self.save_dir, save_filename)
45
+ torch.save(network.cpu().state_dict(), save_path)
46
+ if len(gpu_ids) and torch.cuda.is_available():
47
+ network.cuda()
48
+
49
+ # helper loading function that can be used by subclasses
50
+ def load_network(self, network, network_label, epoch_label, save_dir=''):
51
+ save_filename = '%s_net_%s.pth' % (epoch_label, network_label)
52
+ if not save_dir:
53
+ save_dir = self.save_dir
54
+ save_path = os.path.join(save_dir, save_filename)
55
+ if not os.path.isfile(save_path):
56
+ print('%s not exists yet!' % save_path)
57
+ if network_label == 'G':
58
+ raise('Generator must exist!')
59
+ else:
60
+ #network.load_state_dict(torch.load(save_path))
61
+ try:
62
+ network.load_state_dict(torch.load(save_path))
63
+ except:
64
+ pretrained_dict = torch.load(save_path)
65
+ model_dict = network.state_dict()
66
+ try:
67
+ pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
68
+ network.load_state_dict(pretrained_dict)
69
+ if self.opt.verbose:
70
+ print('Pretrained network %s has excessive layers; Only loading layers that are used' % network_label)
71
+ except:
72
+ print('Pretrained network %s has fewer layers; The following are not initialized:' % network_label)
73
+ for k, v in pretrained_dict.items():
74
+ if v.size() == model_dict[k].size():
75
+ model_dict[k] = v
76
+
77
+ if sys.version_info >= (3,0):
78
+ not_initialized = set()
79
+ else:
80
+ from sets import Set
81
+ not_initialized = Set()
82
+
83
+ for k, v in model_dict.items():
84
+ if k not in pretrained_dict or v.size() != pretrained_dict[k].size():
85
+ not_initialized.add(k.split('.')[0])
86
+
87
+ print(sorted(not_initialized))
88
+ network.load_state_dict(model_dict)
89
+
90
+ def update_learning_rate():
91
+ pass
models/models.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+
3
+ def create_model(opt):
4
+ if opt.model == 'pix2pixHD':
5
+ from .pix2pixHD_model import Pix2PixHDModel, InferenceModel
6
+ if opt.isTrain:
7
+ model = Pix2PixHDModel()
8
+ else:
9
+ model = InferenceModel()
10
+ else:
11
+ from .ui_model import UIModel
12
+ model = UIModel()
13
+ model.initialize(opt)
14
+ if opt.verbose:
15
+ print("model [%s] was created" % (model.name()))
16
+
17
+ if opt.isTrain and len(opt.gpu_ids) and not opt.fp16:
18
+ model = torch.nn.DataParallel(model, device_ids=opt.gpu_ids)
19
+
20
+ return model
models/networks.py ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import functools
4
+ from torch.autograd import Variable
5
+ import numpy as np
6
+
7
+ ###############################################################################
8
+ # Functions
9
+ ###############################################################################
10
+ def weights_init(m):
11
+ classname = m.__class__.__name__
12
+ if classname.find('Conv') != -1:
13
+ m.weight.data.normal_(0.0, 0.02)
14
+ elif classname.find('BatchNorm2d') != -1:
15
+ m.weight.data.normal_(1.0, 0.02)
16
+ m.bias.data.fill_(0)
17
+
18
+ def get_norm_layer(norm_type='instance'):
19
+ if norm_type == 'batch':
20
+ norm_layer = functools.partial(nn.BatchNorm2d, affine=True)
21
+ elif norm_type == 'instance':
22
+ norm_layer = functools.partial(nn.InstanceNorm2d, affine=False)
23
+ else:
24
+ raise NotImplementedError('normalization layer [%s] is not found' % norm_type)
25
+ return norm_layer
26
+
27
+ def define_G(input_nc, output_nc, ngf, netG, n_downsample_global=3, n_blocks_global=9, n_local_enhancers=1,
28
+ n_blocks_local=3, norm='instance', gpu_ids=[]):
29
+ norm_layer = get_norm_layer(norm_type=norm)
30
+ if netG == 'global':
31
+ netG = GlobalGenerator(input_nc, output_nc, ngf, n_downsample_global, n_blocks_global, norm_layer)
32
+ elif netG == 'local':
33
+ netG = LocalEnhancer(input_nc, output_nc, ngf, n_downsample_global, n_blocks_global,
34
+ n_local_enhancers, n_blocks_local, norm_layer)
35
+ elif netG == 'encoder':
36
+ netG = Encoder(input_nc, output_nc, ngf, n_downsample_global, norm_layer)
37
+ else:
38
+ raise('generator not implemented!')
39
+ print(netG)
40
+ if len(gpu_ids) > 0:
41
+ assert(torch.cuda.is_available())
42
+ netG.cuda(gpu_ids[0])
43
+ netG.apply(weights_init)
44
+ return netG
45
+
46
+ def define_D(input_nc, ndf, n_layers_D, norm='instance', use_sigmoid=False, num_D=1, getIntermFeat=False, gpu_ids=[]):
47
+ norm_layer = get_norm_layer(norm_type=norm)
48
+ netD = MultiscaleDiscriminator(input_nc, ndf, n_layers_D, norm_layer, use_sigmoid, num_D, getIntermFeat)
49
+ print(netD)
50
+ if len(gpu_ids) > 0:
51
+ assert(torch.cuda.is_available())
52
+ netD.cuda(gpu_ids[0])
53
+ netD.apply(weights_init)
54
+ return netD
55
+
56
+ def print_network(net):
57
+ if isinstance(net, list):
58
+ net = net[0]
59
+ num_params = 0
60
+ for param in net.parameters():
61
+ num_params += param.numel()
62
+ print(net)
63
+ print('Total number of parameters in millions: ',num_params/1000000)
64
+
65
+ ##############################################################################
66
+ # Losses
67
+ ##############################################################################
68
+ class GANLoss(nn.Module):
69
+ def __init__(self, use_lsgan=True, target_real_label=1.0, target_fake_label=0.0,
70
+ tensor=torch.FloatTensor):
71
+ super(GANLoss, self).__init__()
72
+ self.real_label = target_real_label
73
+ self.fake_label = target_fake_label
74
+ self.real_label_var = None
75
+ self.fake_label_var = None
76
+ self.Tensor = tensor
77
+ if use_lsgan:
78
+ self.loss = nn.MSELoss()
79
+ else:
80
+ self.loss = nn.BCELoss()
81
+
82
+ def get_target_tensor(self, input, target_is_real):
83
+ target_tensor = None
84
+ if target_is_real:
85
+ create_label = ((self.real_label_var is None) or
86
+ (self.real_label_var.numel() != input.numel()))
87
+ if create_label:
88
+ real_tensor = self.Tensor(input.size()).fill_(self.real_label)
89
+ self.real_label_var = Variable(real_tensor, requires_grad=False)
90
+ target_tensor = self.real_label_var
91
+ else:
92
+ create_label = ((self.fake_label_var is None) or
93
+ (self.fake_label_var.numel() != input.numel()))
94
+ if create_label:
95
+ fake_tensor = self.Tensor(input.size()).fill_(self.fake_label)
96
+ self.fake_label_var = Variable(fake_tensor, requires_grad=False)
97
+ target_tensor = self.fake_label_var
98
+ return target_tensor
99
+
100
+ def __call__(self, input, target_is_real):
101
+ if isinstance(input[0], list):
102
+ loss = 0
103
+ for input_i in input:
104
+ pred = input_i[-1]
105
+ target_tensor = self.get_target_tensor(pred, target_is_real)
106
+ loss += self.loss(pred, target_tensor)
107
+ return loss
108
+ else:
109
+ target_tensor = self.get_target_tensor(input[-1], target_is_real)
110
+ return self.loss(input[-1], target_tensor)
111
+
112
+ class VGGLoss(nn.Module):
113
+ def __init__(self, gpu_ids):
114
+ super(VGGLoss, self).__init__()
115
+ self.vgg = Vgg19().cuda()
116
+ self.criterion = nn.L1Loss()
117
+ self.weights = [1.0/32, 1.0/16, 1.0/8, 1.0/4, 1.0]
118
+
119
+ def forward(self, x, y):
120
+ x_vgg, y_vgg = self.vgg(x), self.vgg(y)
121
+ loss = 0
122
+ for i in range(len(x_vgg)):
123
+ loss += self.weights[i] * self.criterion(x_vgg[i], y_vgg[i].detach())
124
+ return loss
125
+
126
+ ##############################################################################
127
+ # Generator
128
+ ##############################################################################
129
+ class LocalEnhancer(nn.Module):
130
+ def __init__(self, input_nc, output_nc, ngf=32, n_downsample_global=3, n_blocks_global=9,
131
+ n_local_enhancers=1, n_blocks_local=3, norm_layer=nn.BatchNorm2d, padding_type='reflect'):
132
+ super(LocalEnhancer, self).__init__()
133
+ self.n_local_enhancers = n_local_enhancers
134
+
135
+ ###### global generator model #####
136
+ ngf_global = ngf * (2**n_local_enhancers)
137
+ model_global = GlobalGenerator(input_nc, output_nc, ngf_global, n_downsample_global, n_blocks_global, norm_layer).model
138
+ model_global = [model_global[i] for i in range(len(model_global)-3)] # get rid of final convolution layers
139
+ self.model = nn.Sequential(*model_global)
140
+
141
+ ###### local enhancer layers #####
142
+ for n in range(1, n_local_enhancers+1):
143
+ ### downsample
144
+ ngf_global = ngf * (2**(n_local_enhancers-n))
145
+ model_downsample = [nn.ReflectionPad2d(3), nn.Conv2d(input_nc, ngf_global, kernel_size=7, padding=0),
146
+ norm_layer(ngf_global), nn.ReLU(True),
147
+ nn.Conv2d(ngf_global, ngf_global * 2, kernel_size=3, stride=2, padding=1),
148
+ norm_layer(ngf_global * 2), nn.ReLU(True)]
149
+ ### residual blocks
150
+ model_upsample = []
151
+ for i in range(n_blocks_local):
152
+ model_upsample += [ResnetBlock(ngf_global * 2, padding_type=padding_type, norm_layer=norm_layer)]
153
+
154
+ ### upsample
155
+ model_upsample += [nn.ConvTranspose2d(ngf_global * 2, ngf_global, kernel_size=3, stride=2, padding=1, output_padding=1),
156
+ norm_layer(ngf_global), nn.ReLU(True)]
157
+
158
+ ### final convolution
159
+ if n == n_local_enhancers:
160
+ model_upsample += [nn.ReflectionPad2d(3), nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0), nn.Tanh()]
161
+
162
+ setattr(self, 'model'+str(n)+'_1', nn.Sequential(*model_downsample))
163
+ setattr(self, 'model'+str(n)+'_2', nn.Sequential(*model_upsample))
164
+
165
+ self.downsample = nn.AvgPool2d(3, stride=2, padding=[1, 1], count_include_pad=False)
166
+
167
+ def forward(self, input):
168
+ ### create input pyramid
169
+ input_downsampled = [input]
170
+ for i in range(self.n_local_enhancers):
171
+ input_downsampled.append(self.downsample(input_downsampled[-1]))
172
+
173
+ ### output at coarest level
174
+ output_prev = self.model(input_downsampled[-1])
175
+ ### build up one layer at a time
176
+ for n_local_enhancers in range(1, self.n_local_enhancers+1):
177
+ model_downsample = getattr(self, 'model'+str(n_local_enhancers)+'_1')
178
+ model_upsample = getattr(self, 'model'+str(n_local_enhancers)+'_2')
179
+ input_i = input_downsampled[self.n_local_enhancers-n_local_enhancers]
180
+ output_prev = model_upsample(model_downsample(input_i) + output_prev)
181
+ return output_prev
182
+
183
+ class GlobalGenerator(nn.Module):
184
+ def __init__(self, input_nc, output_nc, ngf=64, n_downsampling=3, n_blocks=9, norm_layer=nn.BatchNorm2d,
185
+ padding_type='reflect'):
186
+ assert(n_blocks >= 0)
187
+ super(GlobalGenerator, self).__init__()
188
+ activation = nn.ReLU(True)
189
+
190
+ model = [nn.ReflectionPad2d(3), nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0), norm_layer(ngf), activation]
191
+ ### downsample
192
+ for i in range(n_downsampling):
193
+ mult = 2**i
194
+ model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3, stride=2, padding=1),
195
+ norm_layer(ngf * mult * 2), activation]
196
+
197
+ ### resnet blocks
198
+ mult = 2**n_downsampling
199
+ for i in range(n_blocks):
200
+ model += [ResnetBlock(ngf * mult, padding_type=padding_type, activation=activation, norm_layer=norm_layer)]
201
+
202
+ ### upsample
203
+ for i in range(n_downsampling):
204
+ mult = 2**(n_downsampling - i)
205
+ model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2), kernel_size=3, stride=2, padding=1, output_padding=1),
206
+ norm_layer(int(ngf * mult / 2)), activation]
207
+ model += [nn.ReflectionPad2d(3), nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0), nn.Tanh()]
208
+ self.model = nn.Sequential(*model)
209
+
210
+ def forward(self, input):
211
+ return self.model(input)
212
+
213
+ # Define a resnet block
214
+ class ResnetBlock(nn.Module):
215
+ def __init__(self, dim, padding_type, norm_layer, activation=nn.ReLU(True), use_dropout=False):
216
+ super(ResnetBlock, self).__init__()
217
+ self.conv_block = self.build_conv_block(dim, padding_type, norm_layer, activation, use_dropout)
218
+
219
+ def build_conv_block(self, dim, padding_type, norm_layer, activation, use_dropout):
220
+ conv_block = []
221
+ p = 0
222
+ if padding_type == 'reflect':
223
+ conv_block += [nn.ReflectionPad2d(1)]
224
+ elif padding_type == 'replicate':
225
+ conv_block += [nn.ReplicationPad2d(1)]
226
+ elif padding_type == 'zero':
227
+ p = 1
228
+ else:
229
+ raise NotImplementedError('padding [%s] is not implemented' % padding_type)
230
+
231
+ conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p),
232
+ norm_layer(dim),
233
+ activation]
234
+ if use_dropout:
235
+ conv_block += [nn.Dropout(0.5)]
236
+
237
+ p = 0
238
+ if padding_type == 'reflect':
239
+ conv_block += [nn.ReflectionPad2d(1)]
240
+ elif padding_type == 'replicate':
241
+ conv_block += [nn.ReplicationPad2d(1)]
242
+ elif padding_type == 'zero':
243
+ p = 1
244
+ else:
245
+ raise NotImplementedError('padding [%s] is not implemented' % padding_type)
246
+ conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=p),
247
+ norm_layer(dim)]
248
+
249
+ return nn.Sequential(*conv_block)
250
+
251
+ def forward(self, x):
252
+ out = x + self.conv_block(x)
253
+ return out
254
+
255
+ class Encoder(nn.Module):
256
+ def __init__(self, input_nc, output_nc, ngf=32, n_downsampling=4, norm_layer=nn.BatchNorm2d):
257
+ super(Encoder, self).__init__()
258
+ self.output_nc = output_nc
259
+
260
+ model = [nn.ReflectionPad2d(3), nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0),
261
+ norm_layer(ngf), nn.ReLU(True)]
262
+ ### downsample
263
+ for i in range(n_downsampling):
264
+ mult = 2**i
265
+ model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3, stride=2, padding=1),
266
+ norm_layer(ngf * mult * 2), nn.ReLU(True)]
267
+
268
+ ### upsample
269
+ for i in range(n_downsampling):
270
+ mult = 2**(n_downsampling - i)
271
+ model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2), kernel_size=3, stride=2, padding=1, output_padding=1),
272
+ norm_layer(int(ngf * mult / 2)), nn.ReLU(True)]
273
+
274
+ model += [nn.ReflectionPad2d(3), nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0), nn.Tanh()]
275
+ self.model = nn.Sequential(*model)
276
+
277
+ def forward(self, input, inst):
278
+ outputs = self.model(input)
279
+
280
+ # instance-wise average pooling
281
+ outputs_mean = outputs.clone()
282
+ inst_list = np.unique(inst.cpu().numpy().astype(int))
283
+ for i in inst_list:
284
+ for b in range(input.size()[0]):
285
+ indices = (inst[b:b+1] == int(i)).nonzero() # n x 4
286
+ for j in range(self.output_nc):
287
+ output_ins = outputs[indices[:,0] + b, indices[:,1] + j, indices[:,2], indices[:,3]]
288
+ mean_feat = torch.mean(output_ins).expand_as(output_ins)
289
+ outputs_mean[indices[:,0] + b, indices[:,1] + j, indices[:,2], indices[:,3]] = mean_feat
290
+ return outputs_mean
291
+
292
+ class MultiscaleDiscriminator(nn.Module):
293
+ def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d,
294
+ use_sigmoid=False, num_D=3, getIntermFeat=False):
295
+ super(MultiscaleDiscriminator, self).__init__()
296
+ self.num_D = num_D
297
+ self.n_layers = n_layers
298
+ self.getIntermFeat = getIntermFeat
299
+
300
+ for i in range(num_D):
301
+ netD = NLayerDiscriminator(input_nc, ndf, n_layers, norm_layer, use_sigmoid, getIntermFeat)
302
+ if getIntermFeat:
303
+ for j in range(n_layers+2):
304
+ setattr(self, 'scale'+str(i)+'_layer'+str(j), getattr(netD, 'model'+str(j)))
305
+ else:
306
+ setattr(self, 'layer'+str(i), netD.model)
307
+
308
+ self.downsample = nn.AvgPool2d(3, stride=2, padding=[1, 1], count_include_pad=False)
309
+
310
+ def singleD_forward(self, model, input):
311
+ if self.getIntermFeat:
312
+ result = [input]
313
+ for i in range(len(model)):
314
+ result.append(model[i](result[-1]))
315
+ return result[1:]
316
+ else:
317
+ return [model(input)]
318
+
319
+ def forward(self, input):
320
+ num_D = self.num_D
321
+ result = []
322
+ input_downsampled = input
323
+ for i in range(num_D):
324
+ if self.getIntermFeat:
325
+ model = [getattr(self, 'scale'+str(num_D-1-i)+'_layer'+str(j)) for j in range(self.n_layers+2)]
326
+ else:
327
+ model = getattr(self, 'layer'+str(num_D-1-i))
328
+ result.append(self.singleD_forward(model, input_downsampled))
329
+ if i != (num_D-1):
330
+ input_downsampled = self.downsample(input_downsampled)
331
+ return result
332
+
333
+ # Defines the PatchGAN discriminator with the specified arguments.
334
+ class NLayerDiscriminator(nn.Module):
335
+ def __init__(self, input_nc, ndf=64, n_layers=3, norm_layer=nn.BatchNorm2d, use_sigmoid=False, getIntermFeat=False):
336
+ super(NLayerDiscriminator, self).__init__()
337
+ self.getIntermFeat = getIntermFeat
338
+ self.n_layers = n_layers
339
+
340
+ kw = 4
341
+ padw = int(np.ceil((kw-1.0)/2))
342
+ sequence = [[nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, True)]]
343
+
344
+ nf = ndf
345
+ for n in range(1, n_layers):
346
+ nf_prev = nf
347
+ nf = min(nf * 2, 512)
348
+ sequence += [[
349
+ nn.Conv2d(nf_prev, nf, kernel_size=kw, stride=2, padding=padw),
350
+ norm_layer(nf), nn.LeakyReLU(0.2, True)
351
+ ]]
352
+
353
+ nf_prev = nf
354
+ nf = min(nf * 2, 512)
355
+ sequence += [[
356
+ nn.Conv2d(nf_prev, nf, kernel_size=kw, stride=1, padding=padw),
357
+ norm_layer(nf),
358
+ nn.LeakyReLU(0.2, True)
359
+ ]]
360
+
361
+ sequence += [[nn.Conv2d(nf, 1, kernel_size=kw, stride=1, padding=padw)]]
362
+
363
+ if use_sigmoid:
364
+ sequence += [[nn.Sigmoid()]]
365
+
366
+ if getIntermFeat:
367
+ for n in range(len(sequence)):
368
+ setattr(self, 'model'+str(n), nn.Sequential(*sequence[n]))
369
+ else:
370
+ sequence_stream = []
371
+ for n in range(len(sequence)):
372
+ sequence_stream += sequence[n]
373
+ self.model = nn.Sequential(*sequence_stream)
374
+
375
+ def forward(self, input):
376
+ if self.getIntermFeat:
377
+ res = [input]
378
+ for n in range(self.n_layers+2):
379
+ model = getattr(self, 'model'+str(n))
380
+ res.append(model(res[-1]))
381
+ return res[1:]
382
+ else:
383
+ return self.model(input)
384
+
385
+ from torchvision import models
386
+ class Vgg19(torch.nn.Module):
387
+ def __init__(self, requires_grad=False):
388
+ super(Vgg19, self).__init__()
389
+ vgg_pretrained_features = models.vgg19(pretrained=True).features
390
+ self.slice1 = torch.nn.Sequential()
391
+ self.slice2 = torch.nn.Sequential()
392
+ self.slice3 = torch.nn.Sequential()
393
+ self.slice4 = torch.nn.Sequential()
394
+ self.slice5 = torch.nn.Sequential()
395
+ for x in range(2):
396
+ self.slice1.add_module(str(x), vgg_pretrained_features[x])
397
+ for x in range(2, 7):
398
+ self.slice2.add_module(str(x), vgg_pretrained_features[x])
399
+ for x in range(7, 12):
400
+ self.slice3.add_module(str(x), vgg_pretrained_features[x])
401
+ for x in range(12, 21):
402
+ self.slice4.add_module(str(x), vgg_pretrained_features[x])
403
+ for x in range(21, 30):
404
+ self.slice5.add_module(str(x), vgg_pretrained_features[x])
405
+ if not requires_grad:
406
+ for param in self.parameters():
407
+ param.requires_grad = False
408
+
409
+ def forward(self, X):
410
+ h_relu1 = self.slice1(X)
411
+ h_relu2 = self.slice2(h_relu1)
412
+ h_relu3 = self.slice3(h_relu2)
413
+ h_relu4 = self.slice4(h_relu3)
414
+ h_relu5 = self.slice5(h_relu4)
415
+ out = [h_relu1, h_relu2, h_relu3, h_relu4, h_relu5]
416
+ return out
models/pix2pixHD_model.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ import os
4
+ from torch.autograd import Variable
5
+ from util.image_pool import ImagePool
6
+ from .base_model import BaseModel
7
+ from . import networks
8
+
9
+ class Pix2PixHDModel(BaseModel):
10
+ def name(self):
11
+ return 'Pix2PixHDModel'
12
+
13
+ def init_loss_filter(self, use_gan_feat_loss, use_vgg_loss):
14
+ flags = (True, use_gan_feat_loss, use_vgg_loss, True, True)
15
+ def loss_filter(g_gan, g_gan_feat, g_vgg, d_real, d_fake):
16
+ return [l for (l,f) in zip((g_gan,g_gan_feat,g_vgg,d_real,d_fake),flags) if f]
17
+ return loss_filter
18
+
19
+ def initialize(self, opt):
20
+ BaseModel.initialize(self, opt)
21
+ if opt.resize_or_crop != 'none' or not opt.isTrain: # when training at full res this causes OOM
22
+ torch.backends.cudnn.benchmark = True
23
+ self.isTrain = opt.isTrain
24
+ self.use_features = opt.instance_feat or opt.label_feat
25
+ self.gen_features = self.use_features and not self.opt.load_features
26
+ input_nc = opt.label_nc if opt.label_nc != 0 else opt.input_nc
27
+
28
+ ##### define networks
29
+ # Generator network
30
+ netG_input_nc = input_nc
31
+ if not opt.no_instance:
32
+ netG_input_nc += 1
33
+ if self.use_features:
34
+ netG_input_nc += opt.feat_num
35
+ self.netG = networks.define_G(netG_input_nc, opt.output_nc, opt.ngf, opt.netG,
36
+ opt.n_downsample_global, opt.n_blocks_global, opt.n_local_enhancers,
37
+ opt.n_blocks_local, opt.norm, gpu_ids=self.gpu_ids)
38
+ networks.print_network(self.netG)
39
+
40
+ # Discriminator network
41
+ if self.isTrain:
42
+ use_sigmoid = opt.no_lsgan
43
+ netD_input_nc = input_nc + opt.output_nc
44
+ if not opt.no_instance:
45
+ netD_input_nc += 1
46
+ self.netD = networks.define_D(netD_input_nc, opt.ndf, opt.n_layers_D, opt.norm, use_sigmoid,
47
+ opt.num_D, not opt.no_ganFeat_loss, gpu_ids=self.gpu_ids)
48
+ networks.print_network(self.netD)
49
+
50
+ ### Encoder network
51
+ if self.gen_features:
52
+ self.netE = networks.define_G(opt.output_nc, opt.feat_num, opt.nef, 'encoder',
53
+ opt.n_downsample_E, norm=opt.norm, gpu_ids=self.gpu_ids)
54
+ if self.opt.verbose:
55
+ print('---------- Networks initialized -------------')
56
+
57
+ # load networks
58
+ if not self.isTrain or opt.continue_train or opt.load_pretrain:
59
+ pretrained_path = '' if not self.isTrain else opt.load_pretrain
60
+ self.load_network(self.netG, 'G', opt.which_epoch, pretrained_path)
61
+ if self.isTrain:
62
+ self.load_network(self.netD, 'D', opt.which_epoch, pretrained_path)
63
+ if self.gen_features:
64
+ self.load_network(self.netE, 'E', opt.which_epoch, pretrained_path)
65
+
66
+ # set loss functions and optimizers
67
+ if self.isTrain:
68
+ if opt.pool_size > 0 and (len(self.gpu_ids)) > 1:
69
+ raise NotImplementedError("Fake Pool Not Implemented for MultiGPU")
70
+ self.fake_pool = ImagePool(opt.pool_size)
71
+ self.old_lr = opt.lr
72
+
73
+ # define loss functions
74
+ self.loss_filter = self.init_loss_filter(not opt.no_ganFeat_loss, not opt.no_vgg_loss)
75
+
76
+ self.criterionGAN = networks.GANLoss(use_lsgan=not opt.no_lsgan, tensor=self.Tensor)
77
+ self.criterionFeat = torch.nn.L1Loss()
78
+ if not opt.no_vgg_loss:
79
+ self.criterionVGG = networks.VGGLoss(self.gpu_ids)
80
+
81
+
82
+ # Names so we can breakout loss
83
+ self.loss_names = self.loss_filter('G_GAN','G_GAN_Feat','G_VGG','D_real', 'D_fake')
84
+
85
+ # initialize optimizers
86
+ # optimizer G
87
+ if opt.niter_fix_global > 0:
88
+ import sys
89
+ if sys.version_info >= (3,0):
90
+ finetune_list = set()
91
+ else:
92
+ from sets import Set
93
+ finetune_list = Set()
94
+
95
+ params_dict = dict(self.netG.named_parameters())
96
+ params = []
97
+ for key, value in params_dict.items():
98
+ if key.startswith('model' + str(opt.n_local_enhancers)):
99
+ params += [value]
100
+ finetune_list.add(key.split('.')[0])
101
+ print('------------- Only training the local enhancer network (for %d epochs) ------------' % opt.niter_fix_global)
102
+ print('The layers that are finetuned are ', sorted(finetune_list))
103
+ else:
104
+ params = list(self.netG.parameters())
105
+ if self.gen_features:
106
+ params += list(self.netE.parameters())
107
+ self.optimizer_G = torch.optim.Adam(params, lr=opt.lr, betas=(opt.beta1, 0.999))
108
+
109
+ # optimizer D
110
+ params = list(self.netD.parameters())
111
+ self.optimizer_D = torch.optim.Adam(params, lr=opt.lr, betas=(opt.beta1, 0.999))
112
+
113
+ def encode_input(self, label_map, inst_map=None, real_image=None, feat_map=None, infer=False):
114
+ if self.opt.label_nc == 0:
115
+ input_label = label_map.data.cuda()
116
+ else:
117
+ # create one-hot vector for label map
118
+ size = label_map.size()
119
+ oneHot_size = (size[0], self.opt.label_nc, size[2], size[3])
120
+ input_label = torch.cuda.FloatTensor(torch.Size(oneHot_size)).zero_()
121
+ input_label = input_label.scatter_(1, label_map.data.long().cuda(), 1.0)
122
+ if self.opt.data_type == 16:
123
+ input_label = input_label.half()
124
+
125
+ # get edges from instance map
126
+ if not self.opt.no_instance:
127
+ inst_map = inst_map.data.cuda()
128
+ edge_map = self.get_edges(inst_map)
129
+ input_label = torch.cat((input_label, edge_map), dim=1)
130
+ input_label = Variable(input_label, volatile=infer)
131
+
132
+ # real images for training
133
+ if real_image is not None:
134
+ real_image = Variable(real_image.data.cuda())
135
+
136
+ # instance map for feature encoding
137
+ if self.use_features:
138
+ # get precomputed feature maps
139
+ if self.opt.load_features:
140
+ feat_map = Variable(feat_map.data.cuda())
141
+ if self.opt.label_feat:
142
+ inst_map = label_map.cuda()
143
+
144
+ return input_label, inst_map, real_image, feat_map
145
+
146
+ def discriminate(self, input_label, test_image, use_pool=False):
147
+ input_concat = torch.cat((input_label, test_image.detach()), dim=1)
148
+ if use_pool:
149
+ fake_query = self.fake_pool.query(input_concat)
150
+ return self.netD.forward(fake_query)
151
+ else:
152
+ return self.netD.forward(input_concat)
153
+
154
+ def forward(self, label, inst, image, feat, infer=False):
155
+ # Encode Inputs
156
+ input_label, inst_map, real_image, feat_map = self.encode_input(label, inst, image, feat)
157
+
158
+ # Fake Generation
159
+ if self.use_features:
160
+ if not self.opt.load_features:
161
+ feat_map = self.netE.forward(real_image, inst_map)
162
+ input_concat = torch.cat((input_label, feat_map), dim=1)
163
+ else:
164
+ input_concat = input_label
165
+ fake_image = self.netG.forward(input_concat)
166
+
167
+ # Fake Detection and Loss
168
+ pred_fake_pool = self.discriminate(input_label, fake_image, use_pool=True)
169
+ loss_D_fake = self.criterionGAN(pred_fake_pool, False)
170
+
171
+ # Real Detection and Loss
172
+ pred_real = self.discriminate(input_label, real_image)
173
+ loss_D_real = self.criterionGAN(pred_real, True)
174
+
175
+ # GAN loss (Fake Passability Loss)
176
+ pred_fake = self.netD.forward(torch.cat((input_label, fake_image), dim=1))
177
+ loss_G_GAN = self.criterionGAN(pred_fake, True)
178
+
179
+ # GAN feature matching loss
180
+ loss_G_GAN_Feat = 0
181
+ if not self.opt.no_ganFeat_loss:
182
+ feat_weights = 4.0 / (self.opt.n_layers_D + 1)
183
+ D_weights = 1.0 / self.opt.num_D
184
+ for i in range(self.opt.num_D):
185
+ for j in range(len(pred_fake[i])-1):
186
+ loss_G_GAN_Feat += D_weights * feat_weights * \
187
+ self.criterionFeat(pred_fake[i][j], pred_real[i][j].detach()) * self.opt.lambda_feat
188
+
189
+ # VGG feature matching loss
190
+ loss_G_VGG = 0
191
+ if not self.opt.no_vgg_loss:
192
+ loss_G_VGG = self.criterionVGG(fake_image, real_image) * self.opt.lambda_feat
193
+
194
+ # Only return the fake_B image if necessary to save BW
195
+ return [ self.loss_filter( loss_G_GAN, loss_G_GAN_Feat, loss_G_VGG, loss_D_real, loss_D_fake ), None if not infer else fake_image ]
196
+
197
+ def inference(self, label, inst, image=None):
198
+ # Encode Inputs
199
+ image = Variable(image) if image is not None else None
200
+ input_label, inst_map, real_image, _ = self.encode_input(Variable(label), Variable(inst), image, infer=True)
201
+
202
+ # Fake Generation
203
+ if self.use_features:
204
+ if self.opt.use_encoded_image:
205
+ # encode the real image to get feature map
206
+ feat_map = self.netE.forward(real_image, inst_map)
207
+ else:
208
+ # sample clusters from precomputed features
209
+ feat_map = self.sample_features(inst_map)
210
+ input_concat = torch.cat((input_label, feat_map), dim=1)
211
+ else:
212
+ input_concat = input_label
213
+
214
+ if torch.__version__.startswith('0.4'):
215
+ with torch.no_grad():
216
+ fake_image = self.netG.forward(input_concat)
217
+ else:
218
+ fake_image = self.netG.forward(input_concat)
219
+ return fake_image
220
+
221
+ def sample_features(self, inst):
222
+ # read precomputed feature clusters
223
+ cluster_path = os.path.join(self.opt.checkpoints_dir, self.opt.name, self.opt.cluster_path)
224
+ features_clustered = np.load(cluster_path, encoding='latin1').item()
225
+
226
+ # randomly sample from the feature clusters
227
+ inst_np = inst.cpu().numpy().astype(int)
228
+ feat_map = self.Tensor(inst.size()[0], self.opt.feat_num, inst.size()[2], inst.size()[3])
229
+ for i in np.unique(inst_np):
230
+ label = i if i < 1000 else i//1000
231
+ if label in features_clustered:
232
+ feat = features_clustered[label]
233
+ cluster_idx = np.random.randint(0, feat.shape[0])
234
+
235
+ idx = (inst == int(i)).nonzero()
236
+ for k in range(self.opt.feat_num):
237
+ feat_map[idx[:,0], idx[:,1] + k, idx[:,2], idx[:,3]] = feat[cluster_idx, k]
238
+ if self.opt.data_type==16:
239
+ feat_map = feat_map.half()
240
+ return feat_map
241
+
242
+ def encode_features(self, image, inst):
243
+ image = Variable(image.cuda(), volatile=True)
244
+ feat_num = self.opt.feat_num
245
+ h, w = inst.size()[2], inst.size()[3]
246
+ block_num = 32
247
+ feat_map = self.netE.forward(image, inst.cuda())
248
+ inst_np = inst.cpu().numpy().astype(int)
249
+ feature = {}
250
+ for i in range(self.opt.label_nc):
251
+ feature[i] = np.zeros((0, feat_num+1))
252
+ for i in np.unique(inst_np):
253
+ label = i if i < 1000 else i//1000
254
+ idx = (inst == int(i)).nonzero()
255
+ num = idx.size()[0]
256
+ idx = idx[num//2,:]
257
+ val = np.zeros((1, feat_num+1))
258
+ for k in range(feat_num):
259
+ val[0, k] = feat_map[idx[0], idx[1] + k, idx[2], idx[3]].data[0]
260
+ val[0, feat_num] = float(num) / (h * w // block_num)
261
+ feature[label] = np.append(feature[label], val, axis=0)
262
+ return feature
263
+
264
+ def get_edges(self, t):
265
+ edge = torch.cuda.ByteTensor(t.size()).zero_()
266
+ edge[:,:,:,1:] = edge[:,:,:,1:] | (t[:,:,:,1:] != t[:,:,:,:-1])
267
+ edge[:,:,:,:-1] = edge[:,:,:,:-1] | (t[:,:,:,1:] != t[:,:,:,:-1])
268
+ edge[:,:,1:,:] = edge[:,:,1:,:] | (t[:,:,1:,:] != t[:,:,:-1,:])
269
+ edge[:,:,:-1,:] = edge[:,:,:-1,:] | (t[:,:,1:,:] != t[:,:,:-1,:])
270
+ if self.opt.data_type==16:
271
+ return edge.half()
272
+ else:
273
+ return edge.float()
274
+
275
+ def save(self, which_epoch):
276
+ self.save_network(self.netG, 'G', which_epoch, self.gpu_ids)
277
+ self.save_network(self.netD, 'D', which_epoch, self.gpu_ids)
278
+ if self.gen_features:
279
+ self.save_network(self.netE, 'E', which_epoch, self.gpu_ids)
280
+
281
+ def update_fixed_params(self):
282
+ # after fixing the global generator for a number of iterations, also start finetuning it
283
+ params = list(self.netG.parameters())
284
+ if self.gen_features:
285
+ params += list(self.netE.parameters())
286
+ self.optimizer_G = torch.optim.Adam(params, lr=self.opt.lr, betas=(self.opt.beta1, 0.999))
287
+ if self.opt.verbose:
288
+ print('------------ Now also finetuning global generator -----------')
289
+
290
+ def update_learning_rate(self):
291
+ lrd = self.opt.lr / self.opt.niter_decay
292
+ lr = self.old_lr - lrd
293
+ for param_group in self.optimizer_D.param_groups:
294
+ param_group['lr'] = lr
295
+ for param_group in self.optimizer_G.param_groups:
296
+ param_group['lr'] = lr
297
+ if self.opt.verbose:
298
+ print('update learning rate: %f -> %f' % (self.old_lr, lr))
299
+ self.old_lr = lr
300
+
301
+ class InferenceModel(Pix2PixHDModel):
302
+ def forward(self, inp):
303
+ label, inst = inp
304
+ return self.inference(label, inst)
305
+
306
+
models/ui_model.py ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch.autograd import Variable
3
+ from collections import OrderedDict
4
+ import numpy as np
5
+ import os
6
+ from PIL import Image
7
+ import util.util as util
8
+ from .base_model import BaseModel
9
+ from . import networks
10
+
11
+ class UIModel(BaseModel):
12
+ def name(self):
13
+ return 'UIModel'
14
+
15
+ def initialize(self, opt):
16
+ assert(not opt.isTrain)
17
+ BaseModel.initialize(self, opt)
18
+ self.use_features = opt.instance_feat or opt.label_feat
19
+
20
+ netG_input_nc = opt.label_nc
21
+ if not opt.no_instance:
22
+ netG_input_nc += 1
23
+ if self.use_features:
24
+ netG_input_nc += opt.feat_num
25
+
26
+ self.netG = networks.define_G(netG_input_nc, opt.output_nc, opt.ngf, opt.netG,
27
+ opt.n_downsample_global, opt.n_blocks_global, opt.n_local_enhancers,
28
+ opt.n_blocks_local, opt.norm, gpu_ids=self.gpu_ids)
29
+ self.load_network(self.netG, 'G', opt.which_epoch)
30
+
31
+ print('---------- Networks initialized -------------')
32
+
33
+ def toTensor(self, img, normalize=False):
34
+ tensor = torch.from_numpy(np.array(img, np.int32, copy=False))
35
+ tensor = tensor.view(1, img.size[1], img.size[0], len(img.mode))
36
+ tensor = tensor.transpose(1, 2).transpose(1, 3).contiguous()
37
+ if normalize:
38
+ return (tensor.float()/255.0 - 0.5) / 0.5
39
+ return tensor.float()
40
+
41
+ def load_image(self, label_path, inst_path, feat_path):
42
+ opt = self.opt
43
+ # read label map
44
+ label_img = Image.open(label_path)
45
+ if label_path.find('face') != -1:
46
+ label_img = label_img.convert('L')
47
+ ow, oh = label_img.size
48
+ w = opt.loadSize
49
+ h = int(w * oh / ow)
50
+ label_img = label_img.resize((w, h), Image.NEAREST)
51
+ label_map = self.toTensor(label_img)
52
+
53
+ # onehot vector input for label map
54
+ self.label_map = label_map.cuda()
55
+ oneHot_size = (1, opt.label_nc, h, w)
56
+ input_label = self.Tensor(torch.Size(oneHot_size)).zero_()
57
+ self.input_label = input_label.scatter_(1, label_map.long().cuda(), 1.0)
58
+
59
+ # read instance map
60
+ if not opt.no_instance:
61
+ inst_img = Image.open(inst_path)
62
+ inst_img = inst_img.resize((w, h), Image.NEAREST)
63
+ self.inst_map = self.toTensor(inst_img).cuda()
64
+ self.edge_map = self.get_edges(self.inst_map)
65
+ self.net_input = Variable(torch.cat((self.input_label, self.edge_map), dim=1), volatile=True)
66
+ else:
67
+ self.net_input = Variable(self.input_label, volatile=True)
68
+
69
+ self.features_clustered = np.load(feat_path).item()
70
+ self.object_map = self.inst_map if opt.instance_feat else self.label_map
71
+
72
+ object_np = self.object_map.cpu().numpy().astype(int)
73
+ self.feat_map = self.Tensor(1, opt.feat_num, h, w).zero_()
74
+ self.cluster_indices = np.zeros(self.opt.label_nc, np.uint8)
75
+ for i in np.unique(object_np):
76
+ label = i if i < 1000 else i//1000
77
+ if label in self.features_clustered:
78
+ feat = self.features_clustered[label]
79
+ np.random.seed(i+1)
80
+ cluster_idx = np.random.randint(0, feat.shape[0])
81
+ self.cluster_indices[label] = cluster_idx
82
+ idx = (self.object_map == i).nonzero()
83
+ self.set_features(idx, feat, cluster_idx)
84
+
85
+ self.net_input_original = self.net_input.clone()
86
+ self.label_map_original = self.label_map.clone()
87
+ self.feat_map_original = self.feat_map.clone()
88
+ if not opt.no_instance:
89
+ self.inst_map_original = self.inst_map.clone()
90
+
91
+ def reset(self):
92
+ self.net_input = self.net_input_prev = self.net_input_original.clone()
93
+ self.label_map = self.label_map_prev = self.label_map_original.clone()
94
+ self.feat_map = self.feat_map_prev = self.feat_map_original.clone()
95
+ if not self.opt.no_instance:
96
+ self.inst_map = self.inst_map_prev = self.inst_map_original.clone()
97
+ self.object_map = self.inst_map if self.opt.instance_feat else self.label_map
98
+
99
+ def undo(self):
100
+ self.net_input = self.net_input_prev
101
+ self.label_map = self.label_map_prev
102
+ self.feat_map = self.feat_map_prev
103
+ if not self.opt.no_instance:
104
+ self.inst_map = self.inst_map_prev
105
+ self.object_map = self.inst_map if self.opt.instance_feat else self.label_map
106
+
107
+ # get boundary map from instance map
108
+ def get_edges(self, t):
109
+ edge = torch.cuda.ByteTensor(t.size()).zero_()
110
+ edge[:,:,:,1:] = edge[:,:,:,1:] | (t[:,:,:,1:] != t[:,:,:,:-1])
111
+ edge[:,:,:,:-1] = edge[:,:,:,:-1] | (t[:,:,:,1:] != t[:,:,:,:-1])
112
+ edge[:,:,1:,:] = edge[:,:,1:,:] | (t[:,:,1:,:] != t[:,:,:-1,:])
113
+ edge[:,:,:-1,:] = edge[:,:,:-1,:] | (t[:,:,1:,:] != t[:,:,:-1,:])
114
+ return edge.float()
115
+
116
+ # change the label at the source position to the label at the target position
117
+ def change_labels(self, click_src, click_tgt):
118
+ y_src, x_src = click_src[0], click_src[1]
119
+ y_tgt, x_tgt = click_tgt[0], click_tgt[1]
120
+ label_src = int(self.label_map[0, 0, y_src, x_src])
121
+ inst_src = self.inst_map[0, 0, y_src, x_src]
122
+ label_tgt = int(self.label_map[0, 0, y_tgt, x_tgt])
123
+ inst_tgt = self.inst_map[0, 0, y_tgt, x_tgt]
124
+
125
+ idx_src = (self.inst_map == inst_src).nonzero()
126
+ # need to change 3 things: label map, instance map, and feature map
127
+ if idx_src.shape:
128
+ # backup current maps
129
+ self.backup_current_state()
130
+
131
+ # change both the label map and the network input
132
+ self.label_map[idx_src[:,0], idx_src[:,1], idx_src[:,2], idx_src[:,3]] = label_tgt
133
+ self.net_input[idx_src[:,0], idx_src[:,1] + label_src, idx_src[:,2], idx_src[:,3]] = 0
134
+ self.net_input[idx_src[:,0], idx_src[:,1] + label_tgt, idx_src[:,2], idx_src[:,3]] = 1
135
+
136
+ # update the instance map (and the network input)
137
+ if inst_tgt > 1000:
138
+ # if different instances have different ids, give the new object a new id
139
+ tgt_indices = (self.inst_map > label_tgt * 1000) & (self.inst_map < (label_tgt+1) * 1000)
140
+ inst_tgt = self.inst_map[tgt_indices].max() + 1
141
+ self.inst_map[idx_src[:,0], idx_src[:,1], idx_src[:,2], idx_src[:,3]] = inst_tgt
142
+ self.net_input[:,-1,:,:] = self.get_edges(self.inst_map)
143
+
144
+ # also copy the source features to the target position
145
+ idx_tgt = (self.inst_map == inst_tgt).nonzero()
146
+ if idx_tgt.shape:
147
+ self.copy_features(idx_src, idx_tgt[0,:])
148
+
149
+ self.fake_image = util.tensor2im(self.single_forward(self.net_input, self.feat_map))
150
+
151
+ # add strokes of target label in the image
152
+ def add_strokes(self, click_src, label_tgt, bw, save):
153
+ # get the region of the new strokes (bw is the brush width)
154
+ size = self.net_input.size()
155
+ h, w = size[2], size[3]
156
+ idx_src = torch.LongTensor(bw**2, 4).fill_(0)
157
+ for i in range(bw):
158
+ idx_src[i*bw:(i+1)*bw, 2] = min(h-1, max(0, click_src[0]-bw//2 + i))
159
+ for j in range(bw):
160
+ idx_src[i*bw+j, 3] = min(w-1, max(0, click_src[1]-bw//2 + j))
161
+ idx_src = idx_src.cuda()
162
+
163
+ # again, need to update 3 things
164
+ if idx_src.shape:
165
+ # backup current maps
166
+ if save:
167
+ self.backup_current_state()
168
+
169
+ # update the label map (and the network input) in the stroke region
170
+ self.label_map[idx_src[:,0], idx_src[:,1], idx_src[:,2], idx_src[:,3]] = label_tgt
171
+ for k in range(self.opt.label_nc):
172
+ self.net_input[idx_src[:,0], idx_src[:,1] + k, idx_src[:,2], idx_src[:,3]] = 0
173
+ self.net_input[idx_src[:,0], idx_src[:,1] + label_tgt, idx_src[:,2], idx_src[:,3]] = 1
174
+
175
+ # update the instance map (and the network input)
176
+ self.inst_map[idx_src[:,0], idx_src[:,1], idx_src[:,2], idx_src[:,3]] = label_tgt
177
+ self.net_input[:,-1,:,:] = self.get_edges(self.inst_map)
178
+
179
+ # also update the features if available
180
+ if self.opt.instance_feat:
181
+ feat = self.features_clustered[label_tgt]
182
+ #np.random.seed(label_tgt+1)
183
+ #cluster_idx = np.random.randint(0, feat.shape[0])
184
+ cluster_idx = self.cluster_indices[label_tgt]
185
+ self.set_features(idx_src, feat, cluster_idx)
186
+
187
+ self.fake_image = util.tensor2im(self.single_forward(self.net_input, self.feat_map))
188
+
189
+ # add an object to the clicked position with selected style
190
+ def add_objects(self, click_src, label_tgt, mask, style_id=0):
191
+ y, x = click_src[0], click_src[1]
192
+ mask = np.transpose(mask, (2, 0, 1))[np.newaxis,...]
193
+ idx_src = torch.from_numpy(mask).cuda().nonzero()
194
+ idx_src[:,2] += y
195
+ idx_src[:,3] += x
196
+
197
+ # backup current maps
198
+ self.backup_current_state()
199
+
200
+ # update label map
201
+ self.label_map[idx_src[:,0], idx_src[:,1], idx_src[:,2], idx_src[:,3]] = label_tgt
202
+ for k in range(self.opt.label_nc):
203
+ self.net_input[idx_src[:,0], idx_src[:,1] + k, idx_src[:,2], idx_src[:,3]] = 0
204
+ self.net_input[idx_src[:,0], idx_src[:,1] + label_tgt, idx_src[:,2], idx_src[:,3]] = 1
205
+
206
+ # update instance map
207
+ self.inst_map[idx_src[:,0], idx_src[:,1], idx_src[:,2], idx_src[:,3]] = label_tgt
208
+ self.net_input[:,-1,:,:] = self.get_edges(self.inst_map)
209
+
210
+ # update feature map
211
+ self.set_features(idx_src, self.feat, style_id)
212
+
213
+ self.fake_image = util.tensor2im(self.single_forward(self.net_input, self.feat_map))
214
+
215
+ def single_forward(self, net_input, feat_map):
216
+ net_input = torch.cat((net_input, feat_map), dim=1)
217
+ fake_image = self.netG.forward(net_input)
218
+
219
+ if fake_image.size()[0] == 1:
220
+ return fake_image.data[0]
221
+ return fake_image.data
222
+
223
+
224
+ # generate all outputs for different styles
225
+ def style_forward(self, click_pt, style_id=-1):
226
+ if click_pt is None:
227
+ self.fake_image = util.tensor2im(self.single_forward(self.net_input, self.feat_map))
228
+ self.crop = None
229
+ self.mask = None
230
+ else:
231
+ instToChange = int(self.object_map[0, 0, click_pt[0], click_pt[1]])
232
+ self.instToChange = instToChange
233
+ label = instToChange if instToChange < 1000 else instToChange//1000
234
+ self.feat = self.features_clustered[label]
235
+ self.fake_image = []
236
+ self.mask = self.object_map == instToChange
237
+ idx = self.mask.nonzero()
238
+ self.get_crop_region(idx)
239
+ if idx.size():
240
+ if style_id == -1:
241
+ (min_y, min_x, max_y, max_x) = self.crop
242
+ ### original
243
+ for cluster_idx in range(self.opt.multiple_output):
244
+ self.set_features(idx, self.feat, cluster_idx)
245
+ fake_image = self.single_forward(self.net_input, self.feat_map)
246
+ fake_image = util.tensor2im(fake_image[:,min_y:max_y,min_x:max_x])
247
+ self.fake_image.append(fake_image)
248
+ """### To speed up previewing different style results, either crop or downsample the label maps
249
+ if instToChange > 1000:
250
+ (min_y, min_x, max_y, max_x) = self.crop
251
+ ### crop
252
+ _, _, h, w = self.net_input.size()
253
+ offset = 512
254
+ y_start, x_start = max(0, min_y-offset), max(0, min_x-offset)
255
+ y_end, x_end = min(h, (max_y + offset)), min(w, (max_x + offset))
256
+ y_region = slice(y_start, y_start+(y_end-y_start)//16*16)
257
+ x_region = slice(x_start, x_start+(x_end-x_start)//16*16)
258
+ net_input = self.net_input[:,:,y_region,x_region]
259
+ for cluster_idx in range(self.opt.multiple_output):
260
+ self.set_features(idx, self.feat, cluster_idx)
261
+ fake_image = self.single_forward(net_input, self.feat_map[:,:,y_region,x_region])
262
+ fake_image = util.tensor2im(fake_image[:,min_y-y_start:max_y-y_start,min_x-x_start:max_x-x_start])
263
+ self.fake_image.append(fake_image)
264
+ else:
265
+ ### downsample
266
+ (min_y, min_x, max_y, max_x) = [crop//2 for crop in self.crop]
267
+ net_input = self.net_input[:,:,::2,::2]
268
+ size = net_input.size()
269
+ net_input_batch = net_input.expand(self.opt.multiple_output, size[1], size[2], size[3])
270
+ for cluster_idx in range(self.opt.multiple_output):
271
+ self.set_features(idx, self.feat, cluster_idx)
272
+ feat_map = self.feat_map[:,:,::2,::2]
273
+ if cluster_idx == 0:
274
+ feat_map_batch = feat_map
275
+ else:
276
+ feat_map_batch = torch.cat((feat_map_batch, feat_map), dim=0)
277
+ fake_image_batch = self.single_forward(net_input_batch, feat_map_batch)
278
+ for i in range(self.opt.multiple_output):
279
+ self.fake_image.append(util.tensor2im(fake_image_batch[i,:,min_y:max_y,min_x:max_x]))"""
280
+
281
+ else:
282
+ self.set_features(idx, self.feat, style_id)
283
+ self.cluster_indices[label] = style_id
284
+ self.fake_image = util.tensor2im(self.single_forward(self.net_input, self.feat_map))
285
+
286
+ def backup_current_state(self):
287
+ self.net_input_prev = self.net_input.clone()
288
+ self.label_map_prev = self.label_map.clone()
289
+ self.inst_map_prev = self.inst_map.clone()
290
+ self.feat_map_prev = self.feat_map.clone()
291
+
292
+ # crop the ROI and get the mask of the object
293
+ def get_crop_region(self, idx):
294
+ size = self.net_input.size()
295
+ h, w = size[2], size[3]
296
+ min_y, min_x = idx[:,2].min(), idx[:,3].min()
297
+ max_y, max_x = idx[:,2].max(), idx[:,3].max()
298
+ crop_min = 128
299
+ if max_y - min_y < crop_min:
300
+ min_y = max(0, (max_y + min_y) // 2 - crop_min // 2)
301
+ max_y = min(h-1, min_y + crop_min)
302
+ if max_x - min_x < crop_min:
303
+ min_x = max(0, (max_x + min_x) // 2 - crop_min // 2)
304
+ max_x = min(w-1, min_x + crop_min)
305
+ self.crop = (min_y, min_x, max_y, max_x)
306
+ self.mask = self.mask[:,:, min_y:max_y, min_x:max_x]
307
+
308
+ # update the feature map once a new object is added or the label is changed
309
+ def update_features(self, cluster_idx, mask=None, click_pt=None):
310
+ self.feat_map_prev = self.feat_map.clone()
311
+ # adding a new object
312
+ if mask is not None:
313
+ y, x = click_pt[0], click_pt[1]
314
+ mask = np.transpose(mask, (2,0,1))[np.newaxis,...]
315
+ idx = torch.from_numpy(mask).cuda().nonzero()
316
+ idx[:,2] += y
317
+ idx[:,3] += x
318
+ # changing the label of an existing object
319
+ else:
320
+ idx = (self.object_map == self.instToChange).nonzero()
321
+
322
+ # update feature map
323
+ self.set_features(idx, self.feat, cluster_idx)
324
+
325
+ # set the class features to the target feature
326
+ def set_features(self, idx, feat, cluster_idx):
327
+ for k in range(self.opt.feat_num):
328
+ self.feat_map[idx[:,0], idx[:,1] + k, idx[:,2], idx[:,3]] = feat[cluster_idx, k]
329
+
330
+ # copy the features at the target position to the source position
331
+ def copy_features(self, idx_src, idx_tgt):
332
+ for k in range(self.opt.feat_num):
333
+ val = self.feat_map[idx_tgt[0], idx_tgt[1] + k, idx_tgt[2], idx_tgt[3]]
334
+ self.feat_map[idx_src[:,0], idx_src[:,1] + k, idx_src[:,2], idx_src[:,3]] = val
335
+
336
+ def get_current_visuals(self, getLabel=False):
337
+ mask = self.mask
338
+ if self.mask is not None:
339
+ mask = np.transpose(self.mask[0].cpu().float().numpy(), (1,2,0)).astype(np.uint8)
340
+
341
+ dict_list = [('fake_image', self.fake_image), ('mask', mask)]
342
+
343
+ if getLabel: # only output label map if needed to save bandwidth
344
+ label = util.tensor2label(self.net_input.data[0], self.opt.label_nc)
345
+ dict_list += [('label', label)]
346
+
347
+ return OrderedDict(dict_list)
options/__init__.py ADDED
File without changes
options/base_options.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import os
3
+ from util import util
4
+ import torch
5
+
6
+ class BaseOptions():
7
+ def __init__(self):
8
+ self.parser = argparse.ArgumentParser()
9
+ self.initialized = False
10
+
11
+ def initialize(self):
12
+ # experiment specifics
13
+ self.parser.add_argument('--name', type=str, default='label2city', help='name of the experiment. It decides where to store samples and models')
14
+ self.parser.add_argument('--gpu_ids', type=str, default='0', help='gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU')
15
+ self.parser.add_argument('--checkpoints_dir', type=str, default='./trained_models', help='models are saved here')
16
+ self.parser.add_argument('--model', type=str, default='pix2pixHD', help='which model to use')
17
+ self.parser.add_argument('--norm', type=str, default='instance', help='instance normalization or batch normalization')
18
+ self.parser.add_argument('--use_dropout', action='store_true', help='use dropout for the generator')
19
+ self.parser.add_argument('--data_type', default=32, type=int, choices=[8, 16, 32], help="Supported data type i.e. 8, 16, 32 bit")
20
+ self.parser.add_argument('--verbose', action='store_true', default=False, help='toggles verbose')
21
+ self.parser.add_argument('--fp16', action='store_true', default=False, help='train with AMP')
22
+ self.parser.add_argument('--local_rank', type=int, default=0, help='local rank for distributed training')
23
+
24
+ # input/output sizes
25
+ self.parser.add_argument('--batchSize', type=int, default=1, help='input batch size')
26
+ self.parser.add_argument('--loadSize', type=int, default=256, help='scale images to this size')
27
+ self.parser.add_argument('--fineSize', type=int, default=256, help='then crop to this size')
28
+ self.parser.add_argument('--label_nc', type=int, default=35, help='# of input label channels')
29
+ self.parser.add_argument('--input_nc', type=int, default=3, help='# of input image channels')
30
+ self.parser.add_argument('--output_nc', type=int, default=3, help='# of output image channels')
31
+
32
+ # for setting inputs
33
+ self.parser.add_argument('--dataroot', type=str, default=r'F:\Datasets\DigestPath\scene_generation\all\1000\256\split\train')
34
+ self.parser.add_argument('--resize_or_crop', type=str, default='scale_width', help='scaling and cropping of images at load time [resize_and_crop|crop|scale_width|scale_width_and_crop]')
35
+ self.parser.add_argument('--serial_batches', action='store_true', help='if true, takes images in order to make batches, otherwise takes them randomly')
36
+ self.parser.add_argument('--no_flip', action='store_true', help='if specified, do not flip the images for data argumentation')
37
+ self.parser.add_argument('--nThreads', default=0, type=int, help='# threads for loading data')
38
+ 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.')
39
+
40
+ # for displays
41
+ self.parser.add_argument('--display_winsize', type=int, default=512, help='display window size')
42
+ self.parser.add_argument('--tf_log', action='store_true', help='if specified, use tensorboard logging. Requires tensorflow installed')
43
+
44
+ # for generator
45
+ self.parser.add_argument('--netG', type=str, default='global', help='selects model to use for netG')
46
+ self.parser.add_argument('--ngf', type=int, default=64, help='# of gen filters in first conv layer')
47
+ self.parser.add_argument('--n_downsample_global', type=int, default=4, help='number of downsampling layers in netG')
48
+ self.parser.add_argument('--n_blocks_global', type=int, default=9, help='number of residual blocks in the global generator network')
49
+ self.parser.add_argument('--n_blocks_local', type=int, default=3, help='number of residual blocks in the local enhancer network')
50
+ self.parser.add_argument('--n_local_enhancers', type=int, default=1, help='number of local enhancers to use')
51
+ self.parser.add_argument('--niter_fix_global', type=int, default=0, help='number of epochs that we only train the outmost local enhancer')
52
+
53
+ # for instance-wise features
54
+ self.parser.add_argument('--no_instance', action='store_true', help='if specified, do *not* add instance map as input')
55
+ self.parser.add_argument('--instance_feat', action='store_true', help='if specified, add encoded instance features as input')
56
+ self.parser.add_argument('--label_feat', action='store_true', help='if specified, add encoded label features as input')
57
+ self.parser.add_argument('--feat_num', type=int, default=3, help='vector length for encoded features')
58
+ self.parser.add_argument('--load_features', action='store_true', help='if specified, load precomputed feature maps')
59
+ self.parser.add_argument('--n_downsample_E', type=int, default=4, help='# of downsampling layers in encoder')
60
+ self.parser.add_argument('--nef', type=int, default=16, help='# of encoder filters in the first conv layer')
61
+ self.parser.add_argument('--n_clusters', type=int, default=10, help='number of clusters for features')
62
+
63
+ self.initialized = True
64
+
65
+ def parse(self, save=True):
66
+ if not self.initialized:
67
+ self.initialize()
68
+ self.opt = self.parser.parse_args()
69
+ self.opt.isTrain = self.isTrain # train or test
70
+
71
+ str_ids = self.opt.gpu_ids.split(',')
72
+ self.opt.gpu_ids = []
73
+ for str_id in str_ids:
74
+ id = int(str_id)
75
+ if id >= 0:
76
+ self.opt.gpu_ids.append(id)
77
+
78
+ # set gpu ids
79
+ if len(self.opt.gpu_ids) > 0:
80
+ torch.cuda.set_device(self.opt.gpu_ids[0])
81
+
82
+ args = vars(self.opt)
83
+
84
+ print('------------ Options -------------')
85
+ for k, v in sorted(args.items()):
86
+ print('%s: %s' % (str(k), str(v)))
87
+ print('-------------- End ----------------')
88
+
89
+ # save to the disk
90
+ expr_dir = os.path.join(self.opt.checkpoints_dir, self.opt.name)
91
+ util.mkdirs(expr_dir)
92
+ if save and not self.opt.continue_train:
93
+ file_name = os.path.join(expr_dir, 'opt.txt')
94
+ with open(file_name, 'wt') as opt_file:
95
+ opt_file.write('------------ Options -------------\n')
96
+ for k, v in sorted(args.items()):
97
+ opt_file.write('%s: %s\n' % (str(k), str(v)))
98
+ opt_file.write('-------------- End ----------------\n')
99
+ return self.opt
options/test_options.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .base_options import BaseOptions
2
+
3
+ class TestOptions(BaseOptions):
4
+ def initialize(self):
5
+ BaseOptions.initialize(self)
6
+ self.parser.add_argument('--ntest', type=int, default=float("inf"), help='# of test examples.')
7
+ self.parser.add_argument('--results_dir', type=str, default='./tmp', help='saves results here.')
8
+ self.parser.add_argument('--aspect_ratio', type=float, default=1.0, help='aspect ratio of result images')
9
+ self.parser.add_argument('--phase', type=str, default='test', help='train, val, test, etc')
10
+ self.parser.add_argument('--which_epoch', type=str, default='latest', help='which epoch to load? set to latest to use latest cached model')
11
+ self.parser.add_argument('--how_many', type=int, default=3000, help='how many test images to run')
12
+ self.parser.add_argument('--cluster_path', type=str, default='features_clustered_010.npy', help='the path for clustered results of encoded features')
13
+ self.parser.add_argument('--use_encoded_image', action='store_true', help='if specified, encode the real image to get the feature map')
14
+ self.parser.add_argument("--export_onnx", type=str, help="export ONNX model to a given file")
15
+ self.parser.add_argument("--engine", type=str, help="run serialized TRT engine")
16
+ self.parser.add_argument("--onnx", type=str, help="run ONNX model via TRT")
17
+ self.isTrain = False
options/train_options.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .base_options import BaseOptions
2
+
3
+ class TrainOptions(BaseOptions):
4
+ def initialize(self):
5
+ BaseOptions.initialize(self)
6
+ # for displays
7
+ self.parser.add_argument('--display_freq', type=int, default=100, help='frequency of showing training results on screen')
8
+ self.parser.add_argument('--print_freq', type=int, default=100, help='frequency of showing training results on console')
9
+ self.parser.add_argument('--save_latest_freq', type=int, default=1000, help='frequency of saving the latest results')
10
+ self.parser.add_argument('--save_epoch_freq', type=int, default=10, help='frequency of saving checkpoints at the end of epochs')
11
+ self.parser.add_argument('--no_html', action='store_true', help='do not save intermediate training results to [opt.checkpoints_dir]/[opt.name]/web/')
12
+ self.parser.add_argument('--debug', action='store_true', help='only do one epoch and displays at each iteration')
13
+
14
+ # for training
15
+ self.parser.add_argument('--continue_train', action='store_true', help='continue training: load the latest model')
16
+ self.parser.add_argument('--load_pretrain', type=str, default='', help='load the pretrained model from the specified location')
17
+ self.parser.add_argument('--which_epoch', type=str, default='latest', help='which epoch to load? set to latest to use latest cached model')
18
+ self.parser.add_argument('--phase', type=str, default='train', help='train, val, test, etc')
19
+ self.parser.add_argument('--niter', type=int, default=100, help='# of iter at starting learning rate')
20
+ self.parser.add_argument('--niter_decay', type=int, default=100, help='# of iter to linearly decay learning rate to zero')
21
+ self.parser.add_argument('--beta1', type=float, default=0.5, help='momentum term of adam')
22
+ self.parser.add_argument('--lr', type=float, default=0.0002, help='initial learning rate for adam')
23
+
24
+ # for discriminators
25
+ self.parser.add_argument('--num_D', type=int, default=2, help='number of discriminators to use')
26
+ self.parser.add_argument('--n_layers_D', type=int, default=3, help='only used if which_model_netD==n_layers')
27
+ self.parser.add_argument('--ndf', type=int, default=64, help='# of discrim filters in first conv layer')
28
+ self.parser.add_argument('--lambda_feat', type=float, default=10.0, help='weight for feature matching loss')
29
+ self.parser.add_argument('--no_ganFeat_loss', action='store_true', help='if specified, do *not* use discriminator feature matching loss')
30
+ self.parser.add_argument('--no_vgg_loss', action='store_true', help='if specified, do *not* use VGG feature matching loss')
31
+ self.parser.add_argument('--no_lsgan', action='store_true', help='do *not* use least square GAN, if false, use vanilla GAN')
32
+ self.parser.add_argument('--pool_size', type=int, default=0, help='the size of image buffer that stores previously generated images')
33
+
34
+ self.isTrain = True
pix2pixhd_test.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from collections import OrderedDict
3
+ from torch.autograd import Variable
4
+ from options.test_options import TestOptions
5
+ from data.data_loader import CreateDataLoader
6
+ from models.models import create_model
7
+ import util.util as util
8
+ from util.visualizer import Visualizer
9
+ from util import html
10
+ import torch
11
+
12
+ opt = TestOptions().parse(save=False)
13
+ opt.nThreads = 0 # test code only supports nThreads = 1 but for Srijay's windows machine it will be 0
14
+ opt.batchSize = 1 # test code only supports batchSize = 1
15
+ opt.serial_batches = True # no shuffle
16
+ opt.no_flip = True # no flip
17
+
18
+ data_loader = CreateDataLoader(opt)
19
+ dataset = data_loader.load_data()
20
+ visualizer = Visualizer(opt)
21
+ # create website
22
+ web_dir = os.path.join(opt.results_dir, opt.name, '%s_%s' % (opt.phase, opt.which_epoch))
23
+ webpage = html.HTML(web_dir, 'Experiment = %s, Phase = %s, Epoch = %s' % (opt.name, opt.phase, opt.which_epoch))
24
+
25
+ # test
26
+ if not opt.engine and not opt.onnx:
27
+ model = create_model(opt)
28
+ if opt.data_type == 16:
29
+ model.half()
30
+ elif opt.data_type == 8:
31
+ model.type(torch.uint8)
32
+
33
+ if opt.verbose:
34
+ print(model)
35
+ else:
36
+ from run_engine import run_trt_engine, run_onnx
37
+
38
+ for i, data in enumerate(dataset):
39
+ if i >= opt.how_many:
40
+ break
41
+ if opt.data_type == 16:
42
+ data['label'] = data['label'].half()
43
+ data['inst'] = data['inst'].half()
44
+ elif opt.data_type == 8:
45
+ data['label'] = data['label'].uint8()
46
+ data['inst'] = data['inst'].uint8()
47
+ if opt.export_onnx:
48
+ print ("Exporting to ONNX: ", opt.export_onnx)
49
+ assert opt.export_onnx.endswith("onnx"), "Export model file should end with .onnx"
50
+ torch.onnx.export(model, [data['label'], data['inst']],
51
+ opt.export_onnx, verbose=True)
52
+ exit(0)
53
+ minibatch = 1
54
+ if opt.engine:
55
+ generated = run_trt_engine(opt.engine, minibatch, [data['label'], data['inst']])
56
+ elif opt.onnx:
57
+ generated = run_onnx(opt.onnx, opt.data_type, minibatch, [data['label'], data['inst']])
58
+ else:
59
+ generated = model.inference(data['label'], data['inst'], data['image'])
60
+
61
+ visuals = OrderedDict([('input_label', util.tensor2label(data['label'][0], opt.label_nc)),
62
+ ('synthesized_image', util.tensor2im(generated.data[0]))])
63
+ img_path = data['path']
64
+ print('process image... %s' % img_path)
65
+ visualizer.save_images(webpage, visuals, img_path)
66
+
67
+ webpage.save()
pixelcnn/gated_pixelcnn.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from torchvision import datasets, transforms
4
+ import numpy as np
5
+ from torchvision.utils import save_image
6
+ import time
7
+ import os
8
+ import sys
9
+
10
+ """
11
+ add vqvae and pixelcnn dirs to path
12
+ make sure you run from vqvae directory
13
+ """
14
+
15
+ current_dir = sys.path.append(os.getcwd())
16
+ pixelcnn_dir = sys.path.append(os.getcwd()+ '/pixelcnn')
17
+
18
+ from pixelcnn.models import GatedPixelCNN
19
+ import utils
20
+
21
+ """
22
+ Hyperparameters
23
+ """
24
+ import argparse
25
+ parser = argparse.ArgumentParser()
26
+
27
+ parser.add_argument("--batch_size", type=int, default=1)
28
+ parser.add_argument("--epochs", type=int, default=100)
29
+ parser.add_argument("--log_interval", type=int, default=100)
30
+ parser.add_argument("-save", action="store_true")
31
+ parser.add_argument("-gen_samples", action="store_true")
32
+
33
+ parser.add_argument("--dataset", type=str, default='LATENT_BLOCK')
34
+ parser.add_argument("--num_workers", type=int, default=0)
35
+ parser.add_argument("--img_dim", type=int, default=64)
36
+ parser.add_argument("--input_dim", type=int, default=1,
37
+ help='1 for grayscale 3 for rgb')
38
+ parser.add_argument("--n_embeddings", type=int, default=3,
39
+ help='number of embeddings from VQ VAE')
40
+ parser.add_argument("--n_layers", type=int, default=5)
41
+ parser.add_argument("--learning_rate", type=float, default=3e-4)
42
+
43
+ args = parser.parse_args()
44
+
45
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
46
+
47
+ """
48
+ data loaders
49
+ """
50
+ _, _, train_loader, test_loader, _ = utils.load_data_and_data_loaders('LATENT_BLOCK', args.batch_size)
51
+
52
+ model = GatedPixelCNN(args.n_embeddings, args.img_dim**2, args.n_layers).to(device)
53
+ criterion = nn.CrossEntropyLoss().cuda()
54
+ opt = torch.optim.Adam(model.parameters(), lr=args.learning_rate)
55
+
56
+
57
+ """
58
+ train, test, and log
59
+ """
60
+
61
+ def train():
62
+ train_loss = []
63
+ for batch_idx, (x, label) in enumerate(train_loader):
64
+ start_time = time.time()
65
+ # if args.dataset == 'LATENT_BLOCK':
66
+ # x = (x[:, 0]).cuda()
67
+ # else:
68
+ # x = (x[:, 0] * (K-1)).long().cuda()
69
+ x = x.cuda()
70
+ label = label.cuda()
71
+
72
+ # Train PixelCNN with images
73
+ logits = model(x, label)
74
+ print(logits.shape)
75
+ exit(0)
76
+ logits = logits.permute(0, 2, 3, 1).contiguous()
77
+
78
+ loss = criterion(
79
+ logits.view(-1, args.n_embeddings),
80
+ x.view(-1)
81
+ )
82
+
83
+ opt.zero_grad()
84
+ loss.backward()
85
+ opt.step()
86
+
87
+ train_loss.append(loss.item())
88
+
89
+ if (batch_idx + 1) % args.log_interval == 0:
90
+ print('\tIter: [{}/{} ({:.0f}%)]\tLoss: {} Time: {}'.format(
91
+ batch_idx * len(x), len(train_loader.dataset),
92
+ args.log_interval * batch_idx / len(train_loader),
93
+ np.asarray(train_loss)[-args.log_interval:].mean(0),
94
+ time.time() - start_time
95
+ ))
96
+
97
+
98
+ def test():
99
+ start_time = time.time()
100
+ val_loss = []
101
+ with torch.no_grad():
102
+ for batch_idx, (x, label) in enumerate(test_loader):
103
+ if args.dataset == 'LATENT_BLOCK':
104
+ x = (x[:, 0]).cuda()
105
+ else:
106
+ x = (x[:, 0] * (args.n_embeddings-1)).long().cuda()
107
+ label = label.cuda()
108
+
109
+ logits = model(x, label)
110
+
111
+
112
+ logits = logits.permute(0, 2, 3, 1).contiguous()
113
+ loss = criterion(
114
+ logits.view(-1, args.n_embeddings),
115
+ x.view(-1)
116
+ )
117
+
118
+ val_loss.append(loss.item())
119
+
120
+ print('Validation Completed!\tLoss: {} Time: {}'.format(
121
+ np.asarray(val_loss).mean(0),
122
+ time.time() - start_time
123
+ ))
124
+ return np.asarray(val_loss).mean(0)
125
+
126
+
127
+ def generate_samples(epoch):
128
+ label = torch.arange(10).expand(10, 10).contiguous().view(-1)
129
+ label = label.long().cuda()
130
+
131
+ x_tilde = model.generate(label, shape=(args.img_dim,args.img_dim), batch_size=100)
132
+
133
+ print(x_tilde[0])
134
+
135
+
136
+
137
+ BEST_LOSS = 999
138
+ LAST_SAVED = -1
139
+ for epoch in range(1, args.epochs):
140
+ print("\nEpoch {}:".format(epoch))
141
+ train()
142
+ cur_loss = test()
143
+
144
+ if args.save or cur_loss <= BEST_LOSS:
145
+ BEST_LOSS = cur_loss
146
+ LAST_SAVED = epoch
147
+
148
+ print("Saving model!")
149
+ torch.save(model.state_dict(), 'results/{}_pixelcnn.pt'.format(args.dataset))
150
+ else:
151
+ print("Not saving model! Last saved: {}".format(LAST_SAVED))
152
+ if args.gen_samples:
153
+ generate_samples(epoch)
pixelcnn/models.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+ from torch.distributions.normal import Normal
6
+ from torch.distributions import kl_divergence
7
+
8
+
9
+
10
+ def weights_init(m):
11
+ classname = m.__class__.__name__
12
+ if classname.find('Conv') != -1:
13
+ try:
14
+ nn.init.xavier_uniform_(m.weight.data)
15
+ m.bias.data.fill_(0)
16
+ except AttributeError:
17
+ print("Skipping initialization of ", classname)
18
+
19
+
20
+
21
+ class GatedActivation(nn.Module):
22
+ def __init__(self):
23
+ super().__init__()
24
+
25
+ def forward(self, x):
26
+ x, y = x.chunk(2, dim=1)
27
+ return F.tanh(x) * F.sigmoid(y)
28
+
29
+
30
+ class GatedMaskedConv2d(nn.Module):
31
+ def __init__(self, mask_type, dim, kernel, residual=True, n_classes=10):
32
+ super().__init__()
33
+ assert kernel % 2 == 1, print("Kernel size must be odd")
34
+ self.mask_type = mask_type
35
+ self.residual = residual
36
+
37
+ self.class_cond_embedding = nn.Embedding(
38
+ n_classes, 2 * dim
39
+ )
40
+
41
+ kernel_shp = (kernel // 2 + 1, kernel) # (ceil(n/2), n)
42
+ padding_shp = (kernel // 2, kernel // 2)
43
+ self.vert_stack = nn.Conv2d(
44
+ dim, dim * 2,
45
+ kernel_shp, 1, padding_shp
46
+ )
47
+
48
+ self.vert_to_horiz = nn.Conv2d(2 * dim, 2 * dim, 1)
49
+
50
+ kernel_shp = (1, kernel // 2 + 1)
51
+ padding_shp = (0, kernel // 2)
52
+ self.horiz_stack = nn.Conv2d(
53
+ dim, dim * 2,
54
+ kernel_shp, 1, padding_shp
55
+ )
56
+
57
+ self.horiz_resid = nn.Conv2d(dim, dim, 1)
58
+
59
+ self.gate = GatedActivation()
60
+
61
+ def make_causal(self):
62
+ self.vert_stack.weight.data[:, :, -1].zero_() # Mask final row
63
+ self.horiz_stack.weight.data[:, :, :, -1].zero_() # Mask final column
64
+
65
+ def forward(self, x_v, x_h, h):
66
+ if self.mask_type == 'A':
67
+ self.make_causal()
68
+
69
+ h = self.class_cond_embedding(h)
70
+ h_vert = self.vert_stack(x_v)
71
+ h_vert = h_vert[:, :, :x_v.size(-1), :]
72
+ out_v = self.gate(h_vert + h[:, :, None, None])
73
+
74
+ h_horiz = self.horiz_stack(x_h)
75
+ h_horiz = h_horiz[:, :, :, :x_h.size(-2)]
76
+ v2h = self.vert_to_horiz(h_vert)
77
+
78
+ out = self.gate(v2h + h_horiz + h[:, :, None, None])
79
+ if self.residual:
80
+ out_h = self.horiz_resid(out) + x_h
81
+ else:
82
+ out_h = self.horiz_resid(out)
83
+
84
+ return out_v, out_h
85
+
86
+
87
+ class GatedPixelCNN(nn.Module):
88
+ def __init__(self, input_dim=256, dim=64, n_layers=15, n_classes=10):
89
+ super().__init__()
90
+ self.dim = dim
91
+
92
+ # Create embedding layer to embed input
93
+ self.embedding = nn.Embedding(input_dim, dim)
94
+
95
+ # Building the PixelCNN layer by layer
96
+ self.layers = nn.ModuleList()
97
+
98
+ # Initial block with Mask-A convolution
99
+ # Rest with Mask-B convolutions
100
+ for i in range(n_layers):
101
+ mask_type = 'A' if i == 0 else 'B'
102
+ kernel = 7 if i == 0 else 3
103
+ residual = False if i == 0 else True
104
+
105
+ self.layers.append(
106
+ GatedMaskedConv2d(mask_type, dim, kernel, residual, n_classes)
107
+ )
108
+
109
+ # Add the output layer
110
+ self.output_conv = nn.Sequential(
111
+ nn.Conv2d(dim, 512, 1),
112
+ nn.ReLU(True),
113
+ nn.Conv2d(512, input_dim, 1)
114
+ )
115
+
116
+ self.apply(weights_init)
117
+
118
+ def forward(self, x, label):
119
+ shp = x.size() + (-1, )
120
+ x = self.embedding(x.view(-1)).view(shp) # (B, H, W, C)
121
+ x = x.permute(0, 3, 1, 2) # (B, C, W, H)
122
+
123
+ x_v, x_h = (x, x)
124
+ for i, layer in enumerate(self.layers):
125
+ x_v, x_h = layer(x_v, x_h, label)
126
+
127
+ return self.output_conv(x_h)
128
+
129
+ def generate(self, label, shape=(8, 8), batch_size=64):
130
+ param = next(self.parameters())
131
+ x = torch.zeros(
132
+ (batch_size, *shape),
133
+ dtype=torch.int64, device=param.device
134
+ )
135
+
136
+ for i in range(shape[0]):
137
+ for j in range(shape[1]):
138
+ logits = self.forward(x, label)
139
+ probs = F.softmax(logits[:, :, i, j], -1)
140
+ x.data[:, i, j].copy_(
141
+ probs.multinomial(1).squeeze().data
142
+ )
143
+ return x
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ huggingface_hub==0.22.2
2
+ torch
3
+ torchvision
util/__init__.py ADDED
File without changes
util/html.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dominate
2
+ from dominate.tags import *
3
+ import os
4
+
5
+
6
+ class HTML:
7
+ def __init__(self, web_dir, title, refresh=0):
8
+ self.title = title
9
+ self.web_dir = web_dir
10
+ self.img_dir = os.path.join(self.web_dir, 'images')
11
+ if not os.path.exists(self.web_dir):
12
+ os.makedirs(self.web_dir)
13
+ if not os.path.exists(self.img_dir):
14
+ os.makedirs(self.img_dir)
15
+
16
+ self.doc = dominate.document(title=title)
17
+ if refresh > 0:
18
+ with self.doc.head:
19
+ meta(http_equiv="refresh", content=str(refresh))
20
+
21
+ def get_image_dir(self):
22
+ return self.img_dir
23
+
24
+ def add_header(self, str):
25
+ with self.doc:
26
+ h3(str)
27
+
28
+ def add_table(self, border=1):
29
+ self.t = table(border=border, style="table-layout: fixed;")
30
+ self.doc.add(self.t)
31
+
32
+ def add_images(self, ims, txts, links, width=512):
33
+ self.add_table()
34
+ with self.t:
35
+ with tr():
36
+ for im, txt, link in zip(ims, txts, links):
37
+ with td(style="word-wrap: break-word;", halign="center", valign="top"):
38
+ with p():
39
+ with a(href=os.path.join('images', link)):
40
+ img(style="width:%dpx" % (width), src=os.path.join('images', im))
41
+ br()
42
+ p(txt)
43
+
44
+ def save(self):
45
+ html_file = '%s/index.html' % self.web_dir
46
+ f = open(html_file, 'wt')
47
+ f.write(self.doc.render())
48
+ f.close()
49
+
50
+
51
+ if __name__ == '__main__':
52
+ html = HTML('web/', 'test_html')
53
+ html.add_header('hello world')
54
+
55
+ ims = []
56
+ txts = []
57
+ links = []
58
+ for n in range(4):
59
+ ims.append('image_%d.jpg' % n)
60
+ txts.append('text_%d' % n)
61
+ links.append('image_%d.jpg' % n)
62
+ html.add_images(ims, txts, links)
63
+ html.save()
util/image_pool.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import torch
3
+ from torch.autograd import Variable
4
+ class ImagePool():
5
+ def __init__(self, pool_size):
6
+ self.pool_size = pool_size
7
+ if self.pool_size > 0:
8
+ self.num_imgs = 0
9
+ self.images = []
10
+
11
+ def query(self, images):
12
+ if self.pool_size == 0:
13
+ return images
14
+ return_images = []
15
+ for image in images.data:
16
+ image = torch.unsqueeze(image, 0)
17
+ if self.num_imgs < self.pool_size:
18
+ self.num_imgs = self.num_imgs + 1
19
+ self.images.append(image)
20
+ return_images.append(image)
21
+ else:
22
+ p = random.uniform(0, 1)
23
+ if p > 0.5:
24
+ random_id = random.randint(0, self.pool_size-1)
25
+ tmp = self.images[random_id].clone()
26
+ self.images[random_id] = image
27
+ return_images.append(tmp)
28
+ else:
29
+ return_images.append(image)
30
+ return_images = Variable(torch.cat(return_images, 0))
31
+ return return_images
util/util.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import print_function
2
+ import torch
3
+ import numpy as np
4
+ from PIL import Image
5
+ import numpy as np
6
+ import os
7
+
8
+ # Converts a Tensor into a Numpy array
9
+ # |imtype|: the desired type of the converted numpy array
10
+ def tensor2im(image_tensor, imtype=np.uint8, normalize=True):
11
+ if isinstance(image_tensor, list):
12
+ image_numpy = []
13
+ for i in range(len(image_tensor)):
14
+ image_numpy.append(tensor2im(image_tensor[i], imtype, normalize))
15
+ return image_numpy
16
+ image_numpy = image_tensor.cpu().float().numpy()
17
+ if normalize:
18
+ image_numpy = (np.transpose(image_numpy, (1, 2, 0)) + 1) / 2.0 * 255.0
19
+ else:
20
+ image_numpy = np.transpose(image_numpy, (1, 2, 0)) * 255.0
21
+ image_numpy = np.clip(image_numpy, 0, 255)
22
+ if image_numpy.shape[2] == 1 or image_numpy.shape[2] > 3:
23
+ image_numpy = image_numpy[:,:,0]
24
+ return image_numpy.astype(imtype)
25
+
26
+ # Converts a one-hot tensor into a colorful label map
27
+ def tensor2label(label_tensor, n_label, imtype=np.uint8):
28
+ if n_label == 0:
29
+ return tensor2im(label_tensor, imtype)
30
+ label_tensor = label_tensor.cpu().float()
31
+ if label_tensor.size()[0] > 1:
32
+ label_tensor = label_tensor.max(0, keepdim=True)[1]
33
+ label_tensor = Colorize(n_label)(label_tensor)
34
+ label_numpy = np.transpose(label_tensor.numpy(), (1, 2, 0))
35
+ return label_numpy.astype(imtype)
36
+
37
+ def save_image(image_numpy, image_path):
38
+ image_pil = Image.fromarray(image_numpy)
39
+ image_pil.save(image_path)
40
+
41
+ def mkdirs(paths):
42
+ if isinstance(paths, list) and not isinstance(paths, str):
43
+ for path in paths:
44
+ mkdir(path)
45
+ else:
46
+ mkdir(paths)
47
+
48
+ def mkdir(path):
49
+ if not os.path.exists(path):
50
+ os.makedirs(path)
51
+
52
+ ###############################################################################
53
+ # Code from
54
+ # https://github.com/ycszen/pytorch-seg/blob/master/transform.py
55
+ # Modified so it complies with the Citscape label map colors
56
+ ###############################################################################
57
+ def uint82bin(n, count=8):
58
+ """returns the binary of integer n, count refers to amount of bits"""
59
+ return ''.join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
60
+
61
+ def labelcolormap(N):
62
+ if N == 35: # cityscape
63
+ cmap = np.array([( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), ( 0, 0, 0), (111, 74, 0), ( 81, 0, 81),
64
+ (128, 64,128), (244, 35,232), (250,170,160), (230,150,140), ( 70, 70, 70), (102,102,156), (190,153,153),
65
+ (180,165,180), (150,100,100), (150,120, 90), (153,153,153), (153,153,153), (250,170, 30), (220,220, 0),
66
+ (107,142, 35), (152,251,152), ( 70,130,180), (220, 20, 60), (255, 0, 0), ( 0, 0,142), ( 0, 0, 70),
67
+ ( 0, 60,100), ( 0, 0, 90), ( 0, 0,110), ( 0, 80,100), ( 0, 0,230), (119, 11, 32), ( 0, 0,142)],
68
+ dtype=np.uint8)
69
+ else:
70
+ cmap = np.zeros((N, 3), dtype=np.uint8)
71
+ for i in range(N):
72
+ r, g, b = 0, 0, 0
73
+ id = i
74
+ for j in range(7):
75
+ str_id = uint82bin(id)
76
+ r = r ^ (np.uint8(str_id[-1]) << (7-j))
77
+ g = g ^ (np.uint8(str_id[-2]) << (7-j))
78
+ b = b ^ (np.uint8(str_id[-3]) << (7-j))
79
+ id = id >> 3
80
+ cmap[i, 0] = r
81
+ cmap[i, 1] = g
82
+ cmap[i, 2] = b
83
+ return cmap
84
+
85
+ class Colorize(object):
86
+ def __init__(self, n=35):
87
+ self.cmap = labelcolormap(n)
88
+ self.cmap = torch.from_numpy(self.cmap[:n])
89
+
90
+ def __call__(self, gray_image):
91
+ size = gray_image.size()
92
+ color_image = torch.ByteTensor(3, size[1], size[2]).fill_(0)
93
+
94
+ for label in range(0, len(self.cmap)):
95
+ mask = (label == gray_image[0]).cpu()
96
+ color_image[0][mask] = self.cmap[label][0]
97
+ color_image[1][mask] = self.cmap[label][1]
98
+ color_image[2][mask] = self.cmap[label][2]
99
+
100
+ return color_image
util/visualizer.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import os
3
+ import ntpath
4
+ import time
5
+ from . import util
6
+ from . import html
7
+ import scipy.misc
8
+ try:
9
+ from StringIO import StringIO # Python 2.7
10
+ except ImportError:
11
+ from io import BytesIO # Python 3.x
12
+
13
+ class Visualizer():
14
+ def __init__(self, opt):
15
+ # self.opt = opt
16
+ self.tf_log = opt.tf_log
17
+ self.use_html = opt.isTrain and not opt.no_html
18
+ self.win_size = opt.display_winsize
19
+ self.name = opt.name
20
+ if self.tf_log:
21
+ import tensorflow as tf
22
+ self.tf = tf
23
+ self.log_dir = os.path.join(opt.checkpoints_dir, opt.name, 'logs')
24
+ self.writer = tf.summary.FileWriter(self.log_dir)
25
+
26
+ if self.use_html:
27
+ self.web_dir = os.path.join(opt.checkpoints_dir, opt.name, 'web')
28
+ self.img_dir = os.path.join(self.web_dir, 'images')
29
+ print('create web directory %s...' % self.web_dir)
30
+ util.mkdirs([self.web_dir, self.img_dir])
31
+ self.log_name = os.path.join(opt.checkpoints_dir, opt.name, 'loss_log.txt')
32
+ with open(self.log_name, "a") as log_file:
33
+ now = time.strftime("%c")
34
+ log_file.write('================ Training Loss (%s) ================\n' % now)
35
+
36
+ # |visuals|: dictionary of images to display or save
37
+ def display_current_results(self, visuals, epoch, step):
38
+ if self.tf_log: # show images in tensorboard output
39
+ img_summaries = []
40
+ for label, image_numpy in visuals.items():
41
+ # Write the image to a string
42
+ try:
43
+ s = StringIO()
44
+ except:
45
+ s = BytesIO()
46
+ scipy.misc.toimage(image_numpy).save(s, format="jpeg")
47
+ # Create an Image object
48
+ img_sum = self.tf.Summary.Image(encoded_image_string=s.getvalue(), height=image_numpy.shape[0], width=image_numpy.shape[1])
49
+ # Create a Summary value
50
+ img_summaries.append(self.tf.Summary.Value(tag=label, image=img_sum))
51
+
52
+ # Create and write Summary
53
+ summary = self.tf.Summary(value=img_summaries)
54
+ self.writer.add_summary(summary, step)
55
+
56
+ if self.use_html: # save images to a html file
57
+ for label, image_numpy in visuals.items():
58
+ if isinstance(image_numpy, list):
59
+ for i in range(len(image_numpy)):
60
+ img_path = os.path.join(self.img_dir, 'epoch%.3d_%s_%d.jpg' % (epoch, label, i))
61
+ util.save_image(image_numpy[i], img_path)
62
+ else:
63
+ img_path = os.path.join(self.img_dir, 'epoch%.3d_%s.jpg' % (epoch, label))
64
+ util.save_image(image_numpy, img_path)
65
+
66
+ # update website
67
+ webpage = html.HTML(self.web_dir, 'Experiment name = %s' % self.name, refresh=30)
68
+ for n in range(epoch, 0, -1):
69
+ webpage.add_header('epoch [%d]' % n)
70
+ ims = []
71
+ txts = []
72
+ links = []
73
+
74
+ for label, image_numpy in visuals.items():
75
+ if isinstance(image_numpy, list):
76
+ for i in range(len(image_numpy)):
77
+ img_path = 'epoch%.3d_%s_%d.jpg' % (n, label, i)
78
+ ims.append(img_path)
79
+ txts.append(label+str(i))
80
+ links.append(img_path)
81
+ else:
82
+ img_path = 'epoch%.3d_%s.jpg' % (n, label)
83
+ ims.append(img_path)
84
+ txts.append(label)
85
+ links.append(img_path)
86
+ if len(ims) < 10:
87
+ webpage.add_images(ims, txts, links, width=self.win_size)
88
+ else:
89
+ num = int(round(len(ims)/2.0))
90
+ webpage.add_images(ims[:num], txts[:num], links[:num], width=self.win_size)
91
+ webpage.add_images(ims[num:], txts[num:], links[num:], width=self.win_size)
92
+ webpage.save()
93
+
94
+ # errors: dictionary of error labels and values
95
+ def plot_current_errors(self, errors, step):
96
+ if self.tf_log:
97
+ for tag, value in errors.items():
98
+ summary = self.tf.Summary(value=[self.tf.Summary.Value(tag=tag, simple_value=value)])
99
+ self.writer.add_summary(summary, step)
100
+
101
+ # errors: same format as |errors| of plotCurrentErrors
102
+ def print_current_errors(self, epoch, i, errors, t):
103
+ message = '(epoch: %d, iters: %d, time: %.3f) ' % (epoch, i, t)
104
+ for k, v in errors.items():
105
+ if v != 0:
106
+ message += '%s: %.3f ' % (k, v)
107
+
108
+ print(message)
109
+ with open(self.log_name, "a") as log_file:
110
+ log_file.write('%s\n' % message)
111
+
112
+ # save image to the disk
113
+ def save_images(self, webpage, visuals, image_path):
114
+ image_dir = webpage.get_image_dir()
115
+ short_path = ntpath.basename(image_path[0])
116
+ name = os.path.splitext(short_path)[0]
117
+
118
+ webpage.add_header(name)
119
+ ims = []
120
+ txts = []
121
+ links = []
122
+
123
+ for label, image_numpy in visuals.items():
124
+ image_name = '%s_%s.jpg' % (name, label)
125
+ save_path = os.path.join(image_dir, image_name)
126
+ util.save_image(image_numpy, save_path)
127
+
128
+ ims.append(image_name)
129
+ txts.append(label)
130
+ links.append(image_name)
131
+ webpage.add_images(ims, txts, links, width=self.win_size)