Spaces:
Build error
Build error
Mask weights are added!
Browse files- guided_diffusion/dist_util.py +2 -1
- guided_diffusion/gaussian_diffusion.py +2 -1
- guided_diffusion/image_datasets.py +5 -1
- guided_diffusion/mask.py +338 -0
- guided_diffusion/train_util.py +43 -8
- image_sample.py +77 -13
- image_train.py +5 -2
- scripts/miniFrance.sh +11 -0
- scripts/miniFrance_inpaint.sh +12 -0
- scripts/miniFrance_test.sh +12 -0
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"] = "
|
| 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 |
-
|
|
|
|
| 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 |
-
|
| 123 |
-
|
| 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,
|
|
|
|
| 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 |
-
|
| 91 |
-
|
| 92 |
-
|
| 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
|