Kutluhan commited on
Commit
4459df9
·
1 Parent(s): 6926124

Mask weights are added!

Browse files
guided_diffusion/dist_util.py CHANGED
@@ -23,9 +23,10 @@ def setup_dist():
23
  Setup a distributed process group.
24
  """
25
  if dist.is_initialized():
 
26
  return
27
  # os.environ["CUDA_VISIBLE_DEVICES"] = f"{MPI.COMM_WORLD.Get_rank() % GPUS_PER_NODE}"
28
- os.environ["CUDA_VISIBLE_DEVICES"] = "4"
29
 
30
  comm = MPI.COMM_WORLD
31
  backend = "gloo" if not th.cuda.is_available() else "nccl"
 
23
  Setup a distributed process group.
24
  """
25
  if dist.is_initialized():
26
+ print("Distributed training already initialized")
27
  return
28
  # os.environ["CUDA_VISIBLE_DEVICES"] = f"{MPI.COMM_WORLD.Get_rank() % GPUS_PER_NODE}"
29
+ os.environ["CUDA_VISIBLE_DEVICES"] = "0"
30
 
31
  comm = MPI.COMM_WORLD
32
  backend = "gloo" if not th.cuda.is_available() else "nccl"
guided_diffusion/gaussian_diffusion.py CHANGED
@@ -818,7 +818,8 @@ class GaussianDiffusion:
818
  ModelMeanType.EPSILON: noise,
819
  }[self.model_mean_type]
820
  assert model_output.shape == target.shape == x_start.shape
821
- terms["mse"] = mean_flat((target - model_output) ** 2)
 
822
  if "vb" in terms:
823
  terms["loss"] = terms["mse"] + terms["vb"]
824
  else:
 
818
  ModelMeanType.EPSILON: noise,
819
  }[self.model_mean_type]
820
  assert model_output.shape == target.shape == x_start.shape
821
+ semantic_weights = model_kwargs['semantic_weights']
822
+ terms["mse"] = mean_flat(((target - model_output) ** 2) * semantic_weights)
823
  if "vb" in terms:
824
  terms["loss"] = terms["mse"] + terms["vb"]
825
  else:
guided_diffusion/image_datasets.py CHANGED
@@ -58,6 +58,10 @@ def load_data(
58
  all_files = _list_image_files_recursively(os.path.join(data_dir, 'train' if is_train else 'test', 'images'))
59
  classes = _list_image_files_recursively(os.path.join(data_dir, 'train' if is_train else 'test', 'labels'))
60
  instances = _list_image_files_recursively(os.path.join(data_dir, 'train' if is_train else 'test', 'labels'))
 
 
 
 
61
  else:
62
  raise NotImplementedError('{} not implemented'.format(dataset_mode))
63
 
@@ -150,7 +154,7 @@ class ImageDataset(Dataset):
150
  else:
151
  pil_instance = None
152
 
153
- if self.dataset_mode == 'cityscapes':
154
  arr_image, arr_class, arr_instance = resize_arr([pil_image, pil_class, pil_instance], self.resolution)
155
  else:
156
  if self.is_train:
 
58
  all_files = _list_image_files_recursively(os.path.join(data_dir, 'train' if is_train else 'test', 'images'))
59
  classes = _list_image_files_recursively(os.path.join(data_dir, 'train' if is_train else 'test', 'labels'))
60
  instances = _list_image_files_recursively(os.path.join(data_dir, 'train' if is_train else 'test', 'labels'))
61
+ elif dataset_mode == 'miniFrance':
62
+ all_files = _list_image_files_recursively(os.path.join(data_dir, 'train/images' if is_train else 'val/images'))
63
+ classes = _list_image_files_recursively(os.path.join(data_dir, 'train/label_indices' if is_train else 'val/label_indices'))
64
+ instances = None
65
  else:
66
  raise NotImplementedError('{} not implemented'.format(dataset_mode))
67
 
 
154
  else:
155
  pil_instance = None
156
 
157
+ if self.dataset_mode == 'cityscapes' or self.dataset_mode == 'miniFrance':
158
  arr_image, arr_class, arr_instance = resize_arr([pil_image, pil_class, pil_instance], self.resolution)
159
  else:
160
  if self.is_train:
guided_diffusion/mask.py ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) OpenMMLab. All rights reserved.
2
+ import math
3
+
4
+ import cv2
5
+ import numpy as np
6
+ from PIL import Image, ImageDraw
7
+
8
+
9
+ def random_cropping_bbox(img_shape=(256,256), mask_mode='onedirection'):
10
+ h, w = img_shape
11
+ if mask_mode == 'onedirection':
12
+ _type = np.random.randint(0, 4)
13
+ if _type == 0:
14
+ top, left, height, width = 0, 0, h, w//2
15
+ elif _type == 1:
16
+ top, left, height, width = 0, 0, h//2, w
17
+ elif _type == 2:
18
+ top, left, height, width = h//2, 0, h//2, w
19
+ elif _type == 3:
20
+ top, left, height, width = 0, w//2, h, w//2
21
+ else:
22
+ target_area = (h*w)//2
23
+ width = np.random.randint(target_area//h, w)
24
+ height = target_area//width
25
+ if h==height:
26
+ top = 0
27
+ else:
28
+ top = np.random.randint(0, h-height)
29
+ if w==width:
30
+ left = 0
31
+ else:
32
+ left = np.random.randint(0, w-width)
33
+ return (top, left, height, width)
34
+
35
+ def random_bbox(img_shape=(256,256), max_bbox_shape=(128, 128), max_bbox_delta=40, min_margin=20):
36
+ """Generate a random bbox for the mask on a given image.
37
+
38
+ In our implementation, the max value cannot be obtained since we use
39
+ `np.random.randint`. And this may be different with other standard scripts
40
+ in the community.
41
+
42
+ Args:
43
+ img_shape (tuple[int]): The size of a image, in the form of (h, w).
44
+ max_bbox_shape (int | tuple[int]): Maximum shape of the mask box,
45
+ in the form of (h, w). If it is an integer, the mask box will be
46
+ square.
47
+ max_bbox_delta (int | tuple[int]): Maximum delta of the mask box,
48
+ in the form of (delta_h, delta_w). If it is an integer, delta_h
49
+ and delta_w will be the same. Mask shape will be randomly sampled
50
+ from the range of `max_bbox_shape - max_bbox_delta` and
51
+ `max_bbox_shape`. Default: (40, 40).
52
+ min_margin (int | tuple[int]): The minimum margin size from the
53
+ edges of mask box to the image boarder, in the form of
54
+ (margin_h, margin_w). If it is an integer, margin_h and margin_w
55
+ will be the same. Default: (20, 20).
56
+
57
+ Returns:
58
+ tuple[int]: The generated box, (top, left, h, w).
59
+ """
60
+ if not isinstance(max_bbox_shape, tuple):
61
+ max_bbox_shape = (max_bbox_shape, max_bbox_shape)
62
+ if not isinstance(max_bbox_delta, tuple):
63
+ max_bbox_delta = (max_bbox_delta, max_bbox_delta)
64
+ if not isinstance(min_margin, tuple):
65
+ min_margin = (min_margin, min_margin)
66
+
67
+ img_h, img_w = img_shape[:2]
68
+ max_mask_h, max_mask_w = max_bbox_shape
69
+ max_delta_h, max_delta_w = max_bbox_delta
70
+ margin_h, margin_w = min_margin
71
+
72
+ if max_mask_h > img_h or max_mask_w > img_w:
73
+ raise ValueError(f'mask shape {max_bbox_shape} should be smaller than '
74
+ f'image shape {img_shape}')
75
+ if (max_delta_h // 2 * 2 >= max_mask_h
76
+ or max_delta_w // 2 * 2 >= max_mask_w):
77
+ raise ValueError(f'mask delta {max_bbox_delta} should be smaller than'
78
+ f'mask shape {max_bbox_shape}')
79
+ if img_h - max_mask_h < 2 * margin_h or img_w - max_mask_w < 2 * margin_w:
80
+ raise ValueError(f'Margin {min_margin} cannot be satisfied for img'
81
+ f'shape {img_shape} and mask shape {max_bbox_shape}')
82
+
83
+ # get the max value of (top, left)
84
+ max_top = img_h - margin_h - max_mask_h
85
+ max_left = img_w - margin_w - max_mask_w
86
+ # randomly select a (top, left)
87
+ top = np.random.randint(margin_h, max_top)
88
+ left = np.random.randint(margin_w, max_left)
89
+ # randomly shrink the shape of mask box according to `max_bbox_delta`
90
+ # the center of box is fixed
91
+ delta_top = np.random.randint(0, max_delta_h // 2 + 1)
92
+ delta_left = np.random.randint(0, max_delta_w // 2 + 1)
93
+ top = top + delta_top
94
+ left = left + delta_left
95
+ h = max_mask_h - delta_top
96
+ w = max_mask_w - delta_left
97
+ return (top, left, h, w)
98
+
99
+
100
+ def bbox2mask(img_shape, bbox, dtype='uint8'):
101
+ """Generate mask in ndarray from bbox.
102
+
103
+ The returned mask has the shape of (h, w, 1). '1' indicates the
104
+ hole and '0' indicates the valid regions.
105
+
106
+ We prefer to use `uint8` as the data type of masks, which may be different
107
+ from other codes in the community.
108
+
109
+ Args:
110
+ img_shape (tuple[int]): The size of the image.
111
+ bbox (tuple[int]): Configuration tuple, (top, left, height, width)
112
+ dtype (str): Indicate the data type of returned masks. Default: 'uint8'
113
+
114
+ Return:
115
+ numpy.ndarray: Mask in the shape of (h, w, 1).
116
+ """
117
+
118
+ height, width = img_shape[:2]
119
+
120
+ mask = np.zeros((height, width, 1), dtype=dtype)
121
+ mask[bbox[0]:bbox[0] + bbox[2], bbox[1]:bbox[1] + bbox[3], :] = 1
122
+
123
+ return mask
124
+
125
+
126
+ def brush_stroke_mask(img_shape,
127
+ num_vertices=(4, 12),
128
+ mean_angle=2 * math.pi / 5,
129
+ angle_range=2 * math.pi / 15,
130
+ brush_width=(12, 40),
131
+ max_loops=4,
132
+ dtype='uint8'):
133
+ """Generate free-form mask.
134
+
135
+ The method of generating free-form mask is in the following paper:
136
+ Free-Form Image Inpainting with Gated Convolution.
137
+
138
+ When you set the config of this type of mask. You may note the usage of
139
+ `np.random.randint` and the range of `np.random.randint` is [left, right).
140
+
141
+ We prefer to use `uint8` as the data type of masks, which may be different
142
+ from other codes in the community.
143
+
144
+ TODO: Rewrite the implementation of this function.
145
+
146
+ Args:
147
+ img_shape (tuple[int]): Size of the image.
148
+ num_vertices (int | tuple[int]): Min and max number of vertices. If
149
+ only give an integer, we will fix the number of vertices.
150
+ Default: (4, 12).
151
+ mean_angle (float): Mean value of the angle in each vertex. The angle
152
+ is measured in radians. Default: 2 * math.pi / 5.
153
+ angle_range (float): Range of the random angle.
154
+ Default: 2 * math.pi / 15.
155
+ brush_width (int | tuple[int]): (min_width, max_width). If only give
156
+ an integer, we will fix the width of brush. Default: (12, 40).
157
+ max_loops (int): The max number of for loops of drawing strokes.
158
+ dtype (str): Indicate the data type of returned masks.
159
+ Default: 'uint8'.
160
+
161
+ Returns:
162
+ numpy.ndarray: Mask in the shape of (h, w, 1).
163
+ """
164
+
165
+ img_h, img_w = img_shape[:2]
166
+ if isinstance(num_vertices, int):
167
+ min_num_vertices, max_num_vertices = num_vertices, num_vertices + 1
168
+ elif isinstance(num_vertices, tuple):
169
+ min_num_vertices, max_num_vertices = num_vertices
170
+ else:
171
+ raise TypeError('The type of num_vertices should be int'
172
+ f'or tuple[int], but got type: {num_vertices}')
173
+
174
+ if isinstance(brush_width, tuple):
175
+ min_width, max_width = brush_width
176
+ elif isinstance(brush_width, int):
177
+ min_width, max_width = brush_width, brush_width + 1
178
+ else:
179
+ raise TypeError('The type of brush_width should be int'
180
+ f'or tuple[int], but got type: {brush_width}')
181
+
182
+ average_radius = math.sqrt(img_h * img_h + img_w * img_w) / 8
183
+ mask = Image.new('L', (img_w, img_h), 0)
184
+
185
+ loop_num = np.random.randint(1, max_loops)
186
+ num_vertex_list = np.random.randint(
187
+ min_num_vertices, max_num_vertices, size=loop_num)
188
+ angle_min_list = np.random.uniform(0, angle_range, size=loop_num)
189
+ angle_max_list = np.random.uniform(0, angle_range, size=loop_num)
190
+
191
+ for loop_n in range(loop_num):
192
+ num_vertex = num_vertex_list[loop_n]
193
+ angle_min = mean_angle - angle_min_list[loop_n]
194
+ angle_max = mean_angle + angle_max_list[loop_n]
195
+ angles = []
196
+ vertex = []
197
+
198
+ # set random angle on each vertex
199
+ angles = np.random.uniform(angle_min, angle_max, size=num_vertex)
200
+ reverse_mask = (np.arange(num_vertex, dtype=np.float32) % 2) == 0
201
+ angles[reverse_mask] = 2 * math.pi - angles[reverse_mask]
202
+
203
+ h, w = mask.size
204
+
205
+ # set random vertices
206
+ vertex.append((np.random.randint(0, w), np.random.randint(0, h)))
207
+ r_list = np.random.normal(
208
+ loc=average_radius, scale=average_radius // 2, size=num_vertex)
209
+ for i in range(num_vertex):
210
+ r = np.clip(r_list[i], 0, 2 * average_radius)
211
+ new_x = np.clip(vertex[-1][0] + r * math.cos(angles[i]), 0, w)
212
+ new_y = np.clip(vertex[-1][1] + r * math.sin(angles[i]), 0, h)
213
+ vertex.append((int(new_x), int(new_y)))
214
+ # draw brush strokes according to the vertex and angle list
215
+ draw = ImageDraw.Draw(mask)
216
+ width = np.random.randint(min_width, max_width)
217
+ draw.line(vertex, fill=1, width=width)
218
+ for v in vertex:
219
+ draw.ellipse((v[0] - width // 2, v[1] - width // 2,
220
+ v[0] + width // 2, v[1] + width // 2),
221
+ fill=1)
222
+ # randomly flip the mask
223
+ if np.random.normal() > 0:
224
+ mask.transpose(Image.FLIP_LEFT_RIGHT)
225
+ if np.random.normal() > 0:
226
+ mask.transpose(Image.FLIP_TOP_BOTTOM)
227
+ mask = np.array(mask).astype(dtype=getattr(np, dtype))
228
+ mask = mask[:, :, None]
229
+ return mask
230
+
231
+
232
+ def random_irregular_mask(img_shape,
233
+ num_vertices=(4, 8),
234
+ max_angle=4,
235
+ length_range=(10, 100),
236
+ brush_width=(10, 40),
237
+ dtype='uint8'):
238
+ """Generate random irregular masks.
239
+
240
+ This is a modified version of free-form mask implemented in
241
+ 'brush_stroke_mask'.
242
+
243
+ We prefer to use `uint8` as the data type of masks, which may be different
244
+ from other codes in the community.
245
+
246
+ TODO: Rewrite the implementation of this function.
247
+
248
+ Args:
249
+ img_shape (tuple[int]): Size of the image.
250
+ num_vertices (int | tuple[int]): Min and max number of vertices. If
251
+ only give an integer, we will fix the number of vertices.
252
+ Default: (4, 8).
253
+ max_angle (float): Max value of angle at each vertex. Default 4.0.
254
+ length_range (int | tuple[int]): (min_length, max_length). If only give
255
+ an integer, we will fix the length of brush. Default: (10, 100).
256
+ brush_width (int | tuple[int]): (min_width, max_width). If only give
257
+ an integer, we will fix the width of brush. Default: (10, 40).
258
+ dtype (str): Indicate the data type of returned masks. Default: 'uint8'
259
+
260
+ Returns:
261
+ numpy.ndarray: Mask in the shape of (h, w, 1).
262
+ """
263
+
264
+ h, w = img_shape[:2]
265
+
266
+ mask = np.zeros((h, w), dtype=dtype)
267
+ if isinstance(length_range, int):
268
+ min_length, max_length = length_range, length_range + 1
269
+ elif isinstance(length_range, tuple):
270
+ min_length, max_length = length_range
271
+ else:
272
+ raise TypeError('The type of length_range should be int'
273
+ f'or tuple[int], but got type: {length_range}')
274
+ if isinstance(num_vertices, int):
275
+ min_num_vertices, max_num_vertices = num_vertices, num_vertices + 1
276
+ elif isinstance(num_vertices, tuple):
277
+ min_num_vertices, max_num_vertices = num_vertices
278
+ else:
279
+ raise TypeError('The type of num_vertices should be int'
280
+ f'or tuple[int], but got type: {num_vertices}')
281
+
282
+ if isinstance(brush_width, int):
283
+ min_brush_width, max_brush_width = brush_width, brush_width + 1
284
+ elif isinstance(brush_width, tuple):
285
+ min_brush_width, max_brush_width = brush_width
286
+ else:
287
+ raise TypeError('The type of brush_width should be int'
288
+ f'or tuple[int], but got type: {brush_width}')
289
+
290
+ num_v = np.random.randint(min_num_vertices, max_num_vertices)
291
+
292
+ for i in range(num_v):
293
+ start_x = np.random.randint(w)
294
+ start_y = np.random.randint(h)
295
+ # from the start point, randomly setlect n \in [1, 6] directions.
296
+ direction_num = np.random.randint(1, 6)
297
+ angle_list = np.random.randint(0, max_angle, size=direction_num)
298
+ length_list = np.random.randint(
299
+ min_length, max_length, size=direction_num)
300
+ brush_width_list = np.random.randint(
301
+ min_brush_width, max_brush_width, size=direction_num)
302
+ for direct_n in range(direction_num):
303
+ angle = 0.01 + angle_list[direct_n]
304
+ if i % 2 == 0:
305
+ angle = 2 * math.pi - angle
306
+ length = length_list[direct_n]
307
+ brush_w = brush_width_list[direct_n]
308
+ # compute end point according to the random angle
309
+ end_x = (start_x + length * np.sin(angle)).astype(np.int32)
310
+ end_y = (start_y + length * np.cos(angle)).astype(np.int32)
311
+
312
+ cv2.line(mask, (start_y, start_x), (end_y, end_x), 1, brush_w)
313
+ start_x, start_y = end_x, end_y
314
+ mask = np.expand_dims(mask, axis=2)
315
+
316
+ return mask
317
+
318
+
319
+ def get_irregular_mask(img_shape, area_ratio_range=(0.15, 0.5), **kwargs):
320
+ """Get irregular mask with the constraints in mask ratio
321
+
322
+ Args:
323
+ img_shape (tuple[int]): Size of the image.
324
+ area_ratio_range (tuple(float)): Contain the minimum and maximum area
325
+ ratio. Default: (0.15, 0.5).
326
+
327
+ Returns:
328
+ numpy.ndarray: Mask in the shape of (h, w, 1).
329
+ """
330
+
331
+ mask = random_irregular_mask(img_shape, **kwargs)
332
+ min_ratio, max_ratio = area_ratio_range
333
+
334
+ while not min_ratio < (np.sum(mask) /
335
+ (img_shape[0] * img_shape[1])) < max_ratio:
336
+ mask = random_irregular_mask(img_shape, **kwargs)
337
+
338
+ return mask
guided_diffusion/train_util.py CHANGED
@@ -1,7 +1,8 @@
1
  import copy
2
  import functools
3
  import os
4
-
 
5
  import blobfile as bf
6
  import torch as th
7
  import torch.distributed as dist
@@ -40,6 +41,7 @@ class TrainLoop:
40
  schedule_sampler=None,
41
  weight_decay=0.0,
42
  lr_anneal_steps=0,
 
43
  ):
44
  self.model = model
45
  self.diffusion = diffusion
@@ -62,6 +64,7 @@ class TrainLoop:
62
  self.schedule_sampler = schedule_sampler or UniformSampler(diffusion)
63
  self.weight_decay = weight_decay
64
  self.lr_anneal_steps = lr_anneal_steps
 
65
 
66
  self.step = 0
67
  self.resume_step = 0
@@ -118,10 +121,15 @@ class TrainLoop:
118
  self.resume_step = parse_resume_step_from_filename(resume_checkpoint)
119
  if dist.get_rank() == 0:
120
  logger.log(f"loading model from checkpoint: {resume_checkpoint}...")
 
 
 
 
 
 
121
  self.model.load_state_dict(
122
- th.load(
123
- resume_checkpoint, map_location=dist_util.dev()
124
- )
125
  )
126
 
127
  dist_util.sync_params(self.model.parameters())
@@ -163,7 +171,7 @@ class TrainLoop:
163
  or self.step + self.resume_step < self.lr_anneal_steps
164
  ):
165
  batch, cond = next(self.data)
166
- cond = self.preprocess_input(cond)
167
  self.run_step(batch, cond)
168
  if self.step % self.log_interval == 0:
169
  logger.dumpkvs()
@@ -262,17 +270,33 @@ class TrainLoop:
262
 
263
  dist.barrier()
264
 
265
- def preprocess_input(self, data):
266
  # move to GPU and change data types
267
  data['label'] = data['label'].long()
268
 
269
  # create one-hot label map
270
  label_map = data['label']
271
- bs, _, h, w = label_map.size()
 
272
  nc = self.num_classes
273
  input_label = th.FloatTensor(bs, nc, h, w).zero_()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  input_semantics = input_label.scatter_(1, label_map, 1.0)
275
-
276
  # concatenate instance map if it exists
277
  if 'instance' in data:
278
  inst_map = data['instance']
@@ -284,10 +308,21 @@ class TrainLoop:
284
  input_semantics = input_semantics * mask
285
 
286
  cond = {key: value for key, value in data.items() if key not in ['label', 'instance', 'path', 'label_ori']}
 
287
  cond['y'] = input_semantics
288
 
289
  return cond
290
 
 
 
 
 
 
 
 
 
 
 
291
  def get_edges(self, t):
292
  edge = th.ByteTensor(t.size()).zero_()
293
  edge[:, :, :, 1:] = edge[:, :, :, 1:] | (t[:, :, :, 1:] != t[:, :, :, :-1])
 
1
  import copy
2
  import functools
3
  import os
4
+ import random
5
+ from .mask import (bbox2mask, brush_stroke_mask, get_irregular_mask, random_bbox, random_cropping_bbox)
6
  import blobfile as bf
7
  import torch as th
8
  import torch.distributed as dist
 
41
  schedule_sampler=None,
42
  weight_decay=0.0,
43
  lr_anneal_steps=0,
44
+ inpainting=False,
45
  ):
46
  self.model = model
47
  self.diffusion = diffusion
 
64
  self.schedule_sampler = schedule_sampler or UniformSampler(diffusion)
65
  self.weight_decay = weight_decay
66
  self.lr_anneal_steps = lr_anneal_steps
67
+ self.inpainting = inpainting
68
 
69
  self.step = 0
70
  self.resume_step = 0
 
121
  self.resume_step = parse_resume_step_from_filename(resume_checkpoint)
122
  if dist.get_rank() == 0:
123
  logger.log(f"loading model from checkpoint: {resume_checkpoint}...")
124
+ checkpoint = th.load(resume_checkpoint, map_location=dist_util.dev())
125
+ model_dict = self.model.state_dict()
126
+
127
+ # Filter out mismatched params
128
+ filtered_checkpoint = {k: v for k, v in checkpoint.items() if k in model_dict and v.size() == model_dict[k].size()}
129
+
130
  self.model.load_state_dict(
131
+ filtered_checkpoint,
132
+ strict=False
 
133
  )
134
 
135
  dist_util.sync_params(self.model.parameters())
 
171
  or self.step + self.resume_step < self.lr_anneal_steps
172
  ):
173
  batch, cond = next(self.data)
174
+ cond = self.preprocess_input(batch, cond)
175
  self.run_step(batch, cond)
176
  if self.step % self.log_interval == 0:
177
  logger.dumpkvs()
 
270
 
271
  dist.barrier()
272
 
273
+ def preprocess_input(self, batch, data):
274
  # move to GPU and change data types
275
  data['label'] = data['label'].long()
276
 
277
  # create one-hot label map
278
  label_map = data['label']
279
+ bs, c, h, w = label_map.size()
280
+ # print(label_map.shape, batch.shape)
281
  nc = self.num_classes
282
  input_label = th.FloatTensor(bs, nc, h, w).zero_()
283
+ if self.inpainting:
284
+ unique_per_batch = [th.unique(x) for x in label_map]
285
+ bypass_label_indices = [th.randperm(len(x))[:random.randint(1, len(x))] for x in unique_per_batch]
286
+ bypass_labels = [x[bypass_label_indices[idx]] for idx, x in enumerate(unique_per_batch)]
287
+ for idx, bypass_label in enumerate(bypass_labels):
288
+ if random.random() < 0.3:
289
+ bypassed_label = th.where(th.isin(label_map[idx], bypass_label), 0, label_map[idx])
290
+ bypassed_image = th.where(th.isin(label_map[idx], bypass_label), batch[idx], 0)
291
+ else:
292
+ mask = self.get_mask(image_size=(h, w))
293
+ bypassed_label = th.where(mask == 1, label_map[idx], 0)
294
+ bypassed_image = th.where(mask == 1, 0, batch[idx])
295
+
296
+ label_map[idx, :, :, :] = bypassed_label
297
+ input_label[idx, -3:, :, :] = bypassed_image
298
  input_semantics = input_label.scatter_(1, label_map, 1.0)
299
+ semantic_weights = th.where(input_semantics[:, :1] == 1, 0.1, 2.0)
300
  # concatenate instance map if it exists
301
  if 'instance' in data:
302
  inst_map = data['instance']
 
308
  input_semantics = input_semantics * mask
309
 
310
  cond = {key: value for key, value in data.items() if key not in ['label', 'instance', 'path', 'label_ori']}
311
+ cond['semantic_weights'] = semantic_weights
312
  cond['y'] = input_semantics
313
 
314
  return cond
315
 
316
+ def get_mask(self, image_size):
317
+ if random.random() < 0.5:
318
+ regular_mask = bbox2mask(image_size, random_bbox())
319
+ irregular_mask = brush_stroke_mask(image_size, )
320
+ mask = regular_mask | irregular_mask
321
+ else:
322
+ irregular_mask = brush_stroke_mask(image_size, max_loops=10)
323
+ mask = irregular_mask
324
+ return th.from_numpy(mask).permute(2,0,1)
325
+
326
  def get_edges(self, t):
327
  edge = th.ByteTensor(t.size()).zero_()
328
  edge[:, :, :, 1:] = edge[:, :, :, 1:] | (t[:, :, :, 1:] != t[:, :, :, :-1])
image_sample.py CHANGED
@@ -5,10 +5,11 @@ numpy array. This can be used to produce samples for FID evaluation.
5
 
6
  import argparse
7
  import os
8
-
9
  import torch as th
10
  import torch.distributed as dist
11
  import torchvision as tv
 
12
 
13
  from guided_diffusion.image_datasets import load_data
14
 
@@ -20,10 +21,30 @@ from guided_diffusion.script_util import (
20
  args_to_dict,
21
  )
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  def main():
25
  args = create_argparser().parse_args()
26
-
27
  dist_util.setup_dist()
28
  logger.configure()
29
 
@@ -59,13 +80,16 @@ def main():
59
  os.makedirs(label_path, exist_ok=True)
60
  sample_path = os.path.join(args.results_path, 'samples')
61
  os.makedirs(sample_path, exist_ok=True)
62
-
 
63
  logger.log("sampling...")
64
  all_samples = []
65
  for i, (batch, cond) in enumerate(data):
66
  image = ((batch + 1.0) / 2.0).cuda()
67
  label = (cond['label_ori'].float() / 255.0).cuda()
68
- model_kwargs = preprocess_input(cond, num_classes=args.num_classes)
 
 
69
 
70
  # set hyperparameter
71
  model_kwargs['s'] = args.s
@@ -85,14 +109,17 @@ def main():
85
  gathered_samples = [th.zeros_like(sample) for _ in range(dist.get_world_size())]
86
  dist.all_gather(gathered_samples, sample) # gather not supported with NCCL
87
  all_samples.extend([sample.cpu().numpy() for sample in gathered_samples])
88
-
89
  for j in range(sample.shape[0]):
90
- tv.utils.save_image(image[j], os.path.join(image_path, cond['path'][j].split('/')[-1].split('.')[0] + '.png'))
91
- tv.utils.save_image(sample[j], os.path.join(sample_path, cond['path'][j].split('/')[-1].split('.')[0] + '.png'))
92
- tv.utils.save_image(label[j], os.path.join(label_path, cond['path'][j].split('/')[-1].split('.')[0] + '.png'))
93
-
 
 
 
 
94
  logger.log(f"created {len(all_samples) * args.batch_size} samples")
95
-
96
  if len(all_samples) * args.batch_size > args.num_samples:
97
  break
98
 
@@ -100,7 +127,7 @@ def main():
100
  logger.log("sampling complete")
101
 
102
 
103
- def preprocess_input(data, num_classes):
104
  # move to GPU and change data types
105
  data['label'] = data['label'].long()
106
 
@@ -108,6 +135,31 @@ def preprocess_input(data, num_classes):
108
  label_map = data['label']
109
  bs, _, h, w = label_map.size()
110
  input_label = th.FloatTensor(bs, num_classes, h, w).zero_()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  input_semantics = input_label.scatter_(1, label_map, 1.0)
112
 
113
  # concatenate instance map if it exists
@@ -116,7 +168,18 @@ def preprocess_input(data, num_classes):
116
  instance_edge_map = get_edges(inst_map)
117
  input_semantics = th.cat((input_semantics, instance_edge_map), dim=1)
118
 
119
- return {'y': input_semantics}
 
 
 
 
 
 
 
 
 
 
 
120
 
121
 
122
  def get_edges(t):
@@ -139,7 +202,8 @@ def create_argparser():
139
  model_path="",
140
  results_path="",
141
  is_train=False,
142
- s=1.0
 
143
  )
144
  defaults.update(model_and_diffusion_defaults())
145
  parser = argparse.ArgumentParser()
 
5
 
6
  import argparse
7
  import os
8
+ import random
9
  import torch as th
10
  import torch.distributed as dist
11
  import torchvision as tv
12
+ from guided_diffusion.mask import (bbox2mask, brush_stroke_mask, get_irregular_mask, random_bbox, random_cropping_bbox)
13
 
14
  from guided_diffusion.image_datasets import load_data
15
 
 
21
  args_to_dict,
22
  )
23
 
24
+ label_color_mapping = {
25
+ 0: (0, 0, 0), # No information
26
+ 1: (128, 64, 128), # Urban fabric
27
+ 2: (244, 35, 232), # Industrial, commercial, public, military, private and transport units
28
+ 3: (70, 70, 70), # Mine, dump and construction sites
29
+ 4: (102, 102, 156), # Artificial non-agricultural vegetated areas
30
+ 5: (190, 153, 153), # Arable land (annual crops)
31
+ 6: (153, 153, 153), # Permanent crops
32
+ 7: (250, 170, 30), # Pastures
33
+ 8: (220, 220, 0), # Complex and mixed cultivation patterns
34
+ 9: (107, 142, 35), # Orchards at the fringe of urban classes
35
+ 10: (152, 251, 152), # Forests
36
+ 11: (70, 130, 180), # Herbaceous vegetation associations
37
+ 12: (220, 20, 60), # Open spaces with little or no vegetation
38
+ 13: (255, 0, 0), # Wetlands
39
+ 14: (0, 0, 142), # Water
40
+ 15: (220, 220, 220) # Clouds and shadows
41
+ }
42
+ label_color_mapping_ts = th.tensor(list(label_color_mapping.values()))
43
+ print(label_color_mapping_ts)
44
 
45
  def main():
46
  args = create_argparser().parse_args()
47
+ args.num_classes = args.num_classes + 3 if args.inpainting else args.num_classes
48
  dist_util.setup_dist()
49
  logger.configure()
50
 
 
80
  os.makedirs(label_path, exist_ok=True)
81
  sample_path = os.path.join(args.results_path, 'samples')
82
  os.makedirs(sample_path, exist_ok=True)
83
+ debug_path = os.path.join(args.results_path, 'debug')
84
+ os.makedirs(debug_path, exist_ok=True)
85
  logger.log("sampling...")
86
  all_samples = []
87
  for i, (batch, cond) in enumerate(data):
88
  image = ((batch + 1.0) / 2.0).cuda()
89
  label = (cond['label_ori'].float() / 255.0).cuda()
90
+ model_kwargs = preprocess_input(batch, cond, num_classes=args.num_classes, inpainting=args.inpainting)
91
+ debug_img = model_kwargs['debug_img']
92
+ print(cond['path'])
93
 
94
  # set hyperparameter
95
  model_kwargs['s'] = args.s
 
109
  gathered_samples = [th.zeros_like(sample) for _ in range(dist.get_world_size())]
110
  dist.all_gather(gathered_samples, sample) # gather not supported with NCCL
111
  all_samples.extend([sample.cpu().numpy() for sample in gathered_samples])
 
112
  for j in range(sample.shape[0]):
113
+ print(os.path.join(image_path, cond['path'][j].split('/')[-1]))
114
+ print(os.path.join(sample_path, cond['path'][j].split('/')[-1]))
115
+ print(os.path.join(label_path, cond['path'][j].split('/')[-1]))
116
+ print(os.path.join(debug_path, cond['path'][j].split('/')[-1]))
117
+ tv.utils.save_image(image[j], os.path.join(image_path, cond['path'][j].split('/')[-1]))
118
+ tv.utils.save_image(sample[j], os.path.join(sample_path, cond['path'][j].split('/')[-1]))
119
+ tv.utils.save_image(label[j], os.path.join(label_path, cond['path'][j].split('/')[-1]))
120
+ tv.utils.save_image(debug_img[j], os.path.join(debug_path, cond['path'][j].split('/')[-1]))
121
  logger.log(f"created {len(all_samples) * args.batch_size} samples")
122
+ # break
123
  if len(all_samples) * args.batch_size > args.num_samples:
124
  break
125
 
 
127
  logger.log("sampling complete")
128
 
129
 
130
+ def preprocess_input(batch, data, num_classes, inpainting=False):
131
  # move to GPU and change data types
132
  data['label'] = data['label'].long()
133
 
 
135
  label_map = data['label']
136
  bs, _, h, w = label_map.size()
137
  input_label = th.FloatTensor(bs, num_classes, h, w).zero_()
138
+ debug_img = th.FloatTensor(bs, h, w, 3).zero_()
139
+ if inpainting:
140
+ unique_per_batch = [th.unique(x) for x in label_map]
141
+ bypass_label_indices = [th.randperm(len(x))[:random.randint(0, len(x))] for x in unique_per_batch]
142
+ bypass_labels = [x[bypass_label_indices[idx]] for idx, x in enumerate(unique_per_batch)]
143
+ print(unique_per_batch, bypass_labels)
144
+ for idx, bypass_label in enumerate(bypass_labels):
145
+ debug_norm_img = (batch[idx, :, :, :].permute(1, 2, 0) + 1.0) / 2.0
146
+ if random.random() < 1.0:
147
+ bypassed_label = th.where(th.isin(label_map[idx], bypass_label), 0, label_map[idx])
148
+ bypassed_image = th.where(th.isin(label_map[idx], bypass_label), batch[idx], 0)
149
+ debug_img[idx, :, :, :] = th.where(th.isin(label_map[idx], bypass_label).permute(1,2,0),
150
+ debug_norm_img, label_color_mapping_ts[label_map[idx].squeeze()]/255.0)
151
+ else:
152
+ mask = get_mask(image_size=(h, w))
153
+ bypassed_label = th.where(mask == 1, label_map[idx], 0)
154
+ bypassed_image = th.where(mask == 1, 0, batch[idx])
155
+ debug_img[idx, :, :, :] = th.where(mask.permute(1,2,0) == 1,
156
+ label_color_mapping_ts[label_map[idx].squeeze()]/255.0,
157
+ debug_norm_img)
158
+
159
+
160
+ label_map[idx, :, :, :] = bypassed_label
161
+ input_label[idx, -3:, :, :] = bypassed_image
162
+
163
  input_semantics = input_label.scatter_(1, label_map, 1.0)
164
 
165
  # concatenate instance map if it exists
 
168
  instance_edge_map = get_edges(inst_map)
169
  input_semantics = th.cat((input_semantics, instance_edge_map), dim=1)
170
 
171
+ return {'y': input_semantics, 'debug_img': debug_img.permute(0, 3, 1, 2)}
172
+
173
+ def get_mask(image_size):
174
+ if random.random() < 0.5:
175
+ regular_mask = bbox2mask(image_size, random_bbox())
176
+ irregular_mask = brush_stroke_mask(image_size, )
177
+ mask = regular_mask | irregular_mask
178
+ else:
179
+ irregular_mask = brush_stroke_mask(image_size, max_loops=10)
180
+ mask = irregular_mask
181
+
182
+ return th.from_numpy(mask).permute(2,0,1)
183
 
184
 
185
  def get_edges(t):
 
202
  model_path="",
203
  results_path="",
204
  is_train=False,
205
+ s=1.0,
206
+ inpainting=False
207
  )
208
  defaults.update(model_and_diffusion_defaults())
209
  parser = argparse.ArgumentParser()
image_train.py CHANGED
@@ -19,7 +19,7 @@ from guided_diffusion.train_util import TrainLoop
19
 
20
  def main():
21
  args = create_argparser().parse_args()
22
-
23
  dist_util.setup_dist()
24
  logger.configure()
25
 
@@ -27,6 +27,7 @@ def main():
27
  model, diffusion = create_model_and_diffusion(
28
  **args_to_dict(args, model_and_diffusion_defaults().keys())
29
  )
 
30
  model.to(dist_util.dev())
31
  schedule_sampler = create_named_schedule_sampler(args.schedule_sampler, diffusion)
32
 
@@ -59,6 +60,7 @@ def main():
59
  schedule_sampler=schedule_sampler,
60
  weight_decay=args.weight_decay,
61
  lr_anneal_steps=args.lr_anneal_steps,
 
62
  ).run_loop()
63
 
64
 
@@ -79,7 +81,8 @@ def create_argparser():
79
  resume_checkpoint="",
80
  use_fp16=False,
81
  fp16_scale_growth=1e-3,
82
- is_train=True
 
83
  )
84
  defaults.update(model_and_diffusion_defaults())
85
  parser = argparse.ArgumentParser()
 
19
 
20
  def main():
21
  args = create_argparser().parse_args()
22
+ args.num_classes = args.num_classes + 3 if args.inpainting else args.num_classes
23
  dist_util.setup_dist()
24
  logger.configure()
25
 
 
27
  model, diffusion = create_model_and_diffusion(
28
  **args_to_dict(args, model_and_diffusion_defaults().keys())
29
  )
30
+ print(dist_util.dev())
31
  model.to(dist_util.dev())
32
  schedule_sampler = create_named_schedule_sampler(args.schedule_sampler, diffusion)
33
 
 
60
  schedule_sampler=schedule_sampler,
61
  weight_decay=args.weight_decay,
62
  lr_anneal_steps=args.lr_anneal_steps,
63
+ inpainting=args.inpainting
64
  ).run_loop()
65
 
66
 
 
81
  resume_checkpoint="",
82
  use_fp16=False,
83
  fp16_scale_growth=1e-3,
84
+ is_train=True,
85
+ inpainting=False
86
  )
87
  defaults.update(model_and_diffusion_defaults())
88
  parser = argparse.ArgumentParser()
scripts/miniFrance.sh ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Training
4
+ export OPENAI_LOGDIR='OUTPUT/MiniFrance-SDM-256CH'
5
+ python image_train.py --data_dir ../output2/balanced_patches2 --dataset_mode miniFrance --lr 1e-4 \
6
+ --batch_size 4 \
7
+ --attention_resolutions 32,16,8 --diffusion_steps 1000 --image_size 128 --learn_sigma True \
8
+ --noise_schedule linear --num_channels 256 --num_head_channels 64 --num_res_blocks 2 \
9
+ --resblock_updown True --use_fp16 True --use_scale_shift_norm True \
10
+ --use_checkpoint True --num_classes 16 \
11
+ --class_cond True --no_instance True
scripts/miniFrance_inpaint.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Inpainting Finetune
4
+ export OPENAI_LOGDIR='OUTPUT/MiniFrance-SDM-256CH-INPAINT'
5
+ python image_train.py --data_dir ../output2/balanced_patches2 --dataset_mode miniFrance --lr 2e-5 \
6
+ --batch_size 1 --attention_resolutions 32,16,8 --diffusion_steps 1000 --image_size 256 \
7
+ --learn_sigma True --noise_schedule linear --num_channels 256 --num_head_channels 64 \
8
+ --num_res_blocks 2 --resblock_updown True --use_fp16 True --use_scale_shift_norm True \
9
+ --use_checkpoint True --num_classes 16 \
10
+ --class_cond True --no_instance True \
11
+ --resume_checkpoint OUTPUT/MiniFrance-SDM-256CH/model_best.pt \
12
+ --inpainting True
scripts/miniFrance_test.sh ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Testing
4
+ export OPENAI_LOGDIR='OUTPUT/MiniFrance-SDM-256CH-TEST-INPAINT'
5
+ python image_sample.py --data_dir ../output2/balanced_patches2 --dataset_mode miniFrance \
6
+ --attention_resolutions 32,16,8 --diffusion_steps 1000 --image_size 256 --learn_sigma True \
7
+ --noise_schedule linear --num_channels 256 --num_head_channels 64 --num_res_blocks 2 \
8
+ --resblock_updown True --use_fp16 True --use_scale_shift_norm True --num_classes 16 \
9
+ --class_cond True --no_instance True --batch_size 1 --num_samples 6 \
10
+ --model_path OUTPUT/MiniFrance-SDM-256CH-INPAINT/model016000.pt \
11
+ --results_path RESULTS/MiniFrance-SDM-256CH-INPAINT --s 1.5 \
12
+ --inpainting True