dragynir commited on
Commit
8ed2153
·
1 Parent(s): 432f235
README.md CHANGED
@@ -11,3 +11,31 @@ license: mit
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
14
+
15
+
16
+ Example promts:
17
+
18
+ a handsome man relaxing in a chair, shirt widely unbuttoned, eyes closed, close up, bright red and yellow sunrise, 4k resolution photo realistic
19
+
20
+
21
+ # TODO
22
+
23
+ 0) изучить как обернуть в huggingface app
24
+ Пример как можно сделать апку: https://huggingface.co/spaces/wildoctopus/cloth-segmentation/tree/main
25
+ 1) запушить модель
26
+ 2) Написать UI с RGB цветами (чтобы можно было одежду по шаблону а не изображению генерить)
27
+ 3) Добавить seed в параметры
28
+ 4) Прокинуть остальные параметры
29
+ 5) redis кеширование ответа - ради прикола
30
+
31
+
32
+ # Крупные планы
33
+
34
+ 1) Сделать huggingface space с этой моделью (Написать карточку модели) (RGB три маски с одеждой сделать (255, 0, 0), (0, 255, 0), (0, 0, 255))
35
+ 2) Сделать сервис на основе этой модели
36
+ 3) Перетренировать модель на 1024x1024 с лучшим позиционированием(обучение как в sdxl)
37
+ 4) Придумать другие condition на новых датасетах - которые могут быть полезными
38
+
39
+ # Проект
40
+
41
+ https://huggingface.co/spaces/dragynir/fashion_controlnet
app.py CHANGED
@@ -1,9 +1,43 @@
 
 
1
  import gradio as gr
2
 
 
 
3
 
4
- def greet(name):
5
- return "Hello " + name + "!!"
6
 
 
 
7
 
8
- iface = gr.Interface(fn=greet, inputs="text", outputs="text")
9
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
  import gradio as gr
4
 
5
+ from config import PipelineConfig
6
+ from src.pipeline import FashionPipeline, PipelineOutput
7
 
 
 
8
 
9
+ config = PipelineConfig()
10
+ fashion_pipeline = FashionPipeline(config, device=torch.device('cuda'))
11
 
12
+
13
+ def process(input_image: np.ndarray, prompt: str):
14
+
15
+ output: PipelineOutput = fashion_pipeline(
16
+ control_image=input_image,
17
+ prompt=prompt,
18
+ )
19
+
20
+ return [
21
+ output.control_image,
22
+ output.control_mask,
23
+ output.generated_image,
24
+ ]
25
+
26
+
27
+ block = gr.Blocks().queue()
28
+ with block:
29
+ with gr.Row():
30
+ gr.Markdown("## Control Stable Diffusion with Segmentation Maps")
31
+ with gr.Row():
32
+ with gr.Column():
33
+ input_image = gr.Image(type="numpy")
34
+ prompt = gr.Textbox(label="Prompt")
35
+ run_button = gr.Button(value="Run")
36
+
37
+ with gr.Column():
38
+ result_gallery = gr.Gallery(label='Output', show_label=False, elem_id="gallery")
39
+ ips = [input_image, prompt]
40
+ run_button.click(fn=process, inputs=ips, outputs=[result_gallery])
41
+
42
+
43
+ block.launch()
config.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+
3
+
4
+ import os
5
+ import sys
6
+
7
+ weights_path = os.path.join(sys.path[0], 'weights')
8
+
9
+
10
+ @dataclass
11
+ class PipelineConfig:
12
+ """Fashion Controlnet Pipeline Config."""
13
+
14
+ base_model_path: str = 'stabilityai/stable-diffusion-xl-base-1.0'
15
+ # /pub/home/korostelev/.cache/huggingface/hub/models--stabilityai--stable-diffusion-xl-base-1.0/snapshots/462165984030d82259a11f4367a4eed129e94a7b'
16
+
17
+ controlnet_path: str = r"C:\Users\dragynir\.cache\huggingface\hub\fashion_controlnet"
18
+
19
+ # https://huggingface.co/madebyollin/sdxl-vae-fp16-fix
20
+ vae_path: str = 'madebyollin/sdxl-vae-fp16-fix'
21
+
22
+ segmentation_model_path: str = os.path.join(weights_path, 'cloth_segm.pth')
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ transformers
2
+ diffusers
3
+ accelerate
src/__init__.py ADDED
File without changes
src/pipeline.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+
3
+ from PIL import Image
4
+ import numpy as np
5
+
6
+ from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel, UniPCMultistepScheduler
7
+ import torch
8
+
9
+ from src.preprocess import HWC3
10
+ from src.unet.predictor import generate_mask, load_seg_model
11
+
12
+ from config import PipelineConfig
13
+
14
+
15
+
16
+ @dataclass
17
+ class PipelineOutput:
18
+ control_image: np.ndarray
19
+ control_mask: np.ndarray
20
+ generated_image: np.ndarray
21
+
22
+
23
+ class FashionPipeline:
24
+
25
+ def __init__(
26
+ self,
27
+ config: PipelineConfig,
28
+ device: torch.device,
29
+ ):
30
+ self.config = config
31
+ self.device = device
32
+
33
+ self.segmentation_model = None
34
+ self.controlnet = None
35
+ self.pipeline = None
36
+
37
+ self.__init_pipeline()
38
+
39
+ def __call__(
40
+ self,
41
+ control_image: np.ndarray,
42
+ prompt: str,
43
+ resolution: int = 512,
44
+ num_inference_steps: int = 40,
45
+ ) -> PipelineOutput:
46
+
47
+ # check image format
48
+ control_image = HWC3(control_image)
49
+
50
+ # extract segmentation mask
51
+ control_mask = self.extract_mask(control_image).resize((resolution, resolution))
52
+
53
+ # generate image
54
+ generator = torch.manual_seed(0)
55
+ generated_image = self.pipeline(
56
+ image=control_mask,
57
+ prompt=prompt,
58
+ num_inference_steps=num_inference_steps,
59
+ generator=generator,
60
+ ).images[0]
61
+
62
+ return PipelineOutput(
63
+ control_image=control_image,
64
+ control_mask=control_mask,
65
+ generated_image=generated_image,
66
+ )
67
+
68
+ def extract_mask(self, control_image: np.ndarray) -> Image:
69
+ """Performs segmentation model to extract clothes parts mask."""
70
+ control_mask = generate_mask(control_image, self.segmentation_model, device=self.device)
71
+ control_mask = np.stack([control_mask] * 3, axis=-1)
72
+ control_mask = np.clip((control_mask.astype(np.float32) / 3.0) * 255, 0, 255)
73
+ return Image.fromarray(control_mask.astype('uint8'), 'RGB')
74
+
75
+ def __init_pipeline(self):
76
+ """Init models and SDXL pipeline."""
77
+ self.segmentation_model = load_seg_model(
78
+ self.config.segmentation_model_path,
79
+ device=self.device,
80
+ )
81
+
82
+ self.controlnet = ControlNetModel.from_pretrained(
83
+ self.config.controlnet_path,
84
+ torch_dtype=torch.float16,
85
+ )
86
+
87
+ self.pipeline = StableDiffusionXLControlNetPipeline.from_pretrained(
88
+ self.config.base_model_path,
89
+ controlnet=self.controlnet,
90
+ torch_dtype=torch.float16,
91
+ )
92
+
93
+ self.pipeline.scheduler = UniPCMultistepScheduler.from_config(self.pipeline.scheduler.config)
94
+
95
+ self.pipeline.enable_model_cpu_offload()
src/preprocess.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ def HWC3(x):
5
+ assert x.dtype == np.uint8
6
+ if x.ndim == 2:
7
+ x = x[:, :, None]
8
+ assert x.ndim == 3
9
+ H, W, C = x.shape
10
+ assert C == 1 or C == 3 or C == 4
11
+ if C == 3:
12
+ return x
13
+ if C == 1:
14
+ return np.concatenate([x, x, x], axis=2)
15
+ if C == 4:
16
+ color = x[:, :, 0:3].astype(np.float32)
17
+ alpha = x[:, :, 3:4].astype(np.float32) / 255.0
18
+ y = color * alpha + 255.0 * (1.0 - alpha)
19
+ y = y.clip(0, 255).astype(np.uint8)
20
+ return y
src/unet/__init__.py ADDED
File without changes
src/unet/network.py ADDED
@@ -0,0 +1,559 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+
6
+ class REBNCONV(nn.Module):
7
+ def __init__(self, in_ch=3, out_ch=3, dirate=1):
8
+ super(REBNCONV, self).__init__()
9
+
10
+ self.conv_s1 = nn.Conv2d(
11
+ in_ch, out_ch, 3, padding=1 * dirate, dilation=1 * dirate
12
+ )
13
+ self.bn_s1 = nn.BatchNorm2d(out_ch)
14
+ self.relu_s1 = nn.ReLU(inplace=True)
15
+
16
+ def forward(self, x):
17
+
18
+ hx = x
19
+ xout = self.relu_s1(self.bn_s1(self.conv_s1(hx)))
20
+
21
+ return xout
22
+
23
+
24
+ ## upsample tensor 'src' to have the same spatial size with tensor 'tar'
25
+ def _upsample_like(src, tar):
26
+
27
+ src = F.upsample(src, size=tar.shape[2:], mode="bilinear")
28
+
29
+ return src
30
+
31
+
32
+ ### RSU-7 ###
33
+ class RSU7(nn.Module): # UNet07DRES(nn.Module):
34
+ def __init__(self, in_ch=3, mid_ch=12, out_ch=3):
35
+ super(RSU7, self).__init__()
36
+
37
+ self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)
38
+
39
+ self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
40
+ self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
41
+
42
+ self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=1)
43
+ self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
44
+
45
+ self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=1)
46
+ self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
47
+
48
+ self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=1)
49
+ self.pool4 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
50
+
51
+ self.rebnconv5 = REBNCONV(mid_ch, mid_ch, dirate=1)
52
+ self.pool5 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
53
+
54
+ self.rebnconv6 = REBNCONV(mid_ch, mid_ch, dirate=1)
55
+
56
+ self.rebnconv7 = REBNCONV(mid_ch, mid_ch, dirate=2)
57
+
58
+ self.rebnconv6d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
59
+ self.rebnconv5d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
60
+ self.rebnconv4d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
61
+ self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
62
+ self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
63
+ self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)
64
+
65
+ def forward(self, x):
66
+
67
+ hx = x
68
+ hxin = self.rebnconvin(hx)
69
+
70
+ hx1 = self.rebnconv1(hxin)
71
+ hx = self.pool1(hx1)
72
+
73
+ hx2 = self.rebnconv2(hx)
74
+ hx = self.pool2(hx2)
75
+
76
+ hx3 = self.rebnconv3(hx)
77
+ hx = self.pool3(hx3)
78
+
79
+ hx4 = self.rebnconv4(hx)
80
+ hx = self.pool4(hx4)
81
+
82
+ hx5 = self.rebnconv5(hx)
83
+ hx = self.pool5(hx5)
84
+
85
+ hx6 = self.rebnconv6(hx)
86
+
87
+ hx7 = self.rebnconv7(hx6)
88
+
89
+ hx6d = self.rebnconv6d(torch.cat((hx7, hx6), 1))
90
+ hx6dup = _upsample_like(hx6d, hx5)
91
+
92
+ hx5d = self.rebnconv5d(torch.cat((hx6dup, hx5), 1))
93
+ hx5dup = _upsample_like(hx5d, hx4)
94
+
95
+ hx4d = self.rebnconv4d(torch.cat((hx5dup, hx4), 1))
96
+ hx4dup = _upsample_like(hx4d, hx3)
97
+
98
+ hx3d = self.rebnconv3d(torch.cat((hx4dup, hx3), 1))
99
+ hx3dup = _upsample_like(hx3d, hx2)
100
+
101
+ hx2d = self.rebnconv2d(torch.cat((hx3dup, hx2), 1))
102
+ hx2dup = _upsample_like(hx2d, hx1)
103
+
104
+ hx1d = self.rebnconv1d(torch.cat((hx2dup, hx1), 1))
105
+
106
+ """
107
+ del hx1, hx2, hx3, hx4, hx5, hx6, hx7
108
+ del hx6d, hx5d, hx3d, hx2d
109
+ del hx2dup, hx3dup, hx4dup, hx5dup, hx6dup
110
+ """
111
+
112
+ return hx1d + hxin
113
+
114
+
115
+ ### RSU-6 ###
116
+ class RSU6(nn.Module): # UNet06DRES(nn.Module):
117
+ def __init__(self, in_ch=3, mid_ch=12, out_ch=3):
118
+ super(RSU6, self).__init__()
119
+
120
+ self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)
121
+
122
+ self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
123
+ self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
124
+
125
+ self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=1)
126
+ self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
127
+
128
+ self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=1)
129
+ self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
130
+
131
+ self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=1)
132
+ self.pool4 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
133
+
134
+ self.rebnconv5 = REBNCONV(mid_ch, mid_ch, dirate=1)
135
+
136
+ self.rebnconv6 = REBNCONV(mid_ch, mid_ch, dirate=2)
137
+
138
+ self.rebnconv5d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
139
+ self.rebnconv4d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
140
+ self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
141
+ self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
142
+ self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)
143
+
144
+ def forward(self, x):
145
+
146
+ hx = x
147
+
148
+ hxin = self.rebnconvin(hx)
149
+
150
+ hx1 = self.rebnconv1(hxin)
151
+ hx = self.pool1(hx1)
152
+
153
+ hx2 = self.rebnconv2(hx)
154
+ hx = self.pool2(hx2)
155
+
156
+ hx3 = self.rebnconv3(hx)
157
+ hx = self.pool3(hx3)
158
+
159
+ hx4 = self.rebnconv4(hx)
160
+ hx = self.pool4(hx4)
161
+
162
+ hx5 = self.rebnconv5(hx)
163
+
164
+ hx6 = self.rebnconv6(hx5)
165
+
166
+ hx5d = self.rebnconv5d(torch.cat((hx6, hx5), 1))
167
+ hx5dup = _upsample_like(hx5d, hx4)
168
+
169
+ hx4d = self.rebnconv4d(torch.cat((hx5dup, hx4), 1))
170
+ hx4dup = _upsample_like(hx4d, hx3)
171
+
172
+ hx3d = self.rebnconv3d(torch.cat((hx4dup, hx3), 1))
173
+ hx3dup = _upsample_like(hx3d, hx2)
174
+
175
+ hx2d = self.rebnconv2d(torch.cat((hx3dup, hx2), 1))
176
+ hx2dup = _upsample_like(hx2d, hx1)
177
+
178
+ hx1d = self.rebnconv1d(torch.cat((hx2dup, hx1), 1))
179
+
180
+ """
181
+ del hx1, hx2, hx3, hx4, hx5, hx6
182
+ del hx5d, hx4d, hx3d, hx2d
183
+ del hx2dup, hx3dup, hx4dup, hx5dup
184
+ """
185
+
186
+ return hx1d + hxin
187
+
188
+
189
+ ### RSU-5 ###
190
+ class RSU5(nn.Module): # UNet05DRES(nn.Module):
191
+ def __init__(self, in_ch=3, mid_ch=12, out_ch=3):
192
+ super(RSU5, self).__init__()
193
+
194
+ self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)
195
+
196
+ self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
197
+ self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
198
+
199
+ self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=1)
200
+ self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
201
+
202
+ self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=1)
203
+ self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
204
+
205
+ self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=1)
206
+
207
+ self.rebnconv5 = REBNCONV(mid_ch, mid_ch, dirate=2)
208
+
209
+ self.rebnconv4d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
210
+ self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
211
+ self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
212
+ self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)
213
+
214
+ def forward(self, x):
215
+
216
+ hx = x
217
+
218
+ hxin = self.rebnconvin(hx)
219
+
220
+ hx1 = self.rebnconv1(hxin)
221
+ hx = self.pool1(hx1)
222
+
223
+ hx2 = self.rebnconv2(hx)
224
+ hx = self.pool2(hx2)
225
+
226
+ hx3 = self.rebnconv3(hx)
227
+ hx = self.pool3(hx3)
228
+
229
+ hx4 = self.rebnconv4(hx)
230
+
231
+ hx5 = self.rebnconv5(hx4)
232
+
233
+ hx4d = self.rebnconv4d(torch.cat((hx5, hx4), 1))
234
+ hx4dup = _upsample_like(hx4d, hx3)
235
+
236
+ hx3d = self.rebnconv3d(torch.cat((hx4dup, hx3), 1))
237
+ hx3dup = _upsample_like(hx3d, hx2)
238
+
239
+ hx2d = self.rebnconv2d(torch.cat((hx3dup, hx2), 1))
240
+ hx2dup = _upsample_like(hx2d, hx1)
241
+
242
+ hx1d = self.rebnconv1d(torch.cat((hx2dup, hx1), 1))
243
+
244
+ """
245
+ del hx1, hx2, hx3, hx4, hx5
246
+ del hx4d, hx3d, hx2d
247
+ del hx2dup, hx3dup, hx4dup
248
+ """
249
+
250
+ return hx1d + hxin
251
+
252
+
253
+ ### RSU-4 ###
254
+ class RSU4(nn.Module): # UNet04DRES(nn.Module):
255
+ def __init__(self, in_ch=3, mid_ch=12, out_ch=3):
256
+ super(RSU4, self).__init__()
257
+
258
+ self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)
259
+
260
+ self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
261
+ self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
262
+
263
+ self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=1)
264
+ self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
265
+
266
+ self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=1)
267
+
268
+ self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=2)
269
+
270
+ self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
271
+ self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=1)
272
+ self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)
273
+
274
+ def forward(self, x):
275
+
276
+ hx = x
277
+
278
+ hxin = self.rebnconvin(hx)
279
+
280
+ hx1 = self.rebnconv1(hxin)
281
+ hx = self.pool1(hx1)
282
+
283
+ hx2 = self.rebnconv2(hx)
284
+ hx = self.pool2(hx2)
285
+
286
+ hx3 = self.rebnconv3(hx)
287
+
288
+ hx4 = self.rebnconv4(hx3)
289
+
290
+ hx3d = self.rebnconv3d(torch.cat((hx4, hx3), 1))
291
+ hx3dup = _upsample_like(hx3d, hx2)
292
+
293
+ hx2d = self.rebnconv2d(torch.cat((hx3dup, hx2), 1))
294
+ hx2dup = _upsample_like(hx2d, hx1)
295
+
296
+ hx1d = self.rebnconv1d(torch.cat((hx2dup, hx1), 1))
297
+
298
+ """
299
+ del hx1, hx2, hx3, hx4
300
+ del hx3d, hx2d
301
+ del hx2dup, hx3dup
302
+ """
303
+
304
+ return hx1d + hxin
305
+
306
+
307
+ ### RSU-4F ###
308
+ class RSU4F(nn.Module): # UNet04FRES(nn.Module):
309
+ def __init__(self, in_ch=3, mid_ch=12, out_ch=3):
310
+ super(RSU4F, self).__init__()
311
+
312
+ self.rebnconvin = REBNCONV(in_ch, out_ch, dirate=1)
313
+
314
+ self.rebnconv1 = REBNCONV(out_ch, mid_ch, dirate=1)
315
+ self.rebnconv2 = REBNCONV(mid_ch, mid_ch, dirate=2)
316
+ self.rebnconv3 = REBNCONV(mid_ch, mid_ch, dirate=4)
317
+
318
+ self.rebnconv4 = REBNCONV(mid_ch, mid_ch, dirate=8)
319
+
320
+ self.rebnconv3d = REBNCONV(mid_ch * 2, mid_ch, dirate=4)
321
+ self.rebnconv2d = REBNCONV(mid_ch * 2, mid_ch, dirate=2)
322
+ self.rebnconv1d = REBNCONV(mid_ch * 2, out_ch, dirate=1)
323
+
324
+ def forward(self, x):
325
+
326
+ hx = x
327
+
328
+ hxin = self.rebnconvin(hx)
329
+
330
+ hx1 = self.rebnconv1(hxin)
331
+ hx2 = self.rebnconv2(hx1)
332
+ hx3 = self.rebnconv3(hx2)
333
+
334
+ hx4 = self.rebnconv4(hx3)
335
+
336
+ hx3d = self.rebnconv3d(torch.cat((hx4, hx3), 1))
337
+ hx2d = self.rebnconv2d(torch.cat((hx3d, hx2), 1))
338
+ hx1d = self.rebnconv1d(torch.cat((hx2d, hx1), 1))
339
+
340
+ """
341
+ del hx1, hx2, hx3, hx4
342
+ del hx3d, hx2d
343
+ """
344
+
345
+ return hx1d + hxin
346
+
347
+
348
+ ##### U^2-Net ####
349
+ class U2NET(nn.Module):
350
+ def __init__(self, in_ch=3, out_ch=1):
351
+ super(U2NET, self).__init__()
352
+
353
+ self.stage1 = RSU7(in_ch, 32, 64)
354
+ self.pool12 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
355
+
356
+ self.stage2 = RSU6(64, 32, 128)
357
+ self.pool23 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
358
+
359
+ self.stage3 = RSU5(128, 64, 256)
360
+ self.pool34 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
361
+
362
+ self.stage4 = RSU4(256, 128, 512)
363
+ self.pool45 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
364
+
365
+ self.stage5 = RSU4F(512, 256, 512)
366
+ self.pool56 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
367
+
368
+ self.stage6 = RSU4F(512, 256, 512)
369
+
370
+ # decoder
371
+ self.stage5d = RSU4F(1024, 256, 512)
372
+ self.stage4d = RSU4(1024, 128, 256)
373
+ self.stage3d = RSU5(512, 64, 128)
374
+ self.stage2d = RSU6(256, 32, 64)
375
+ self.stage1d = RSU7(128, 16, 64)
376
+
377
+ self.side1 = nn.Conv2d(64, out_ch, 3, padding=1)
378
+ self.side2 = nn.Conv2d(64, out_ch, 3, padding=1)
379
+ self.side3 = nn.Conv2d(128, out_ch, 3, padding=1)
380
+ self.side4 = nn.Conv2d(256, out_ch, 3, padding=1)
381
+ self.side5 = nn.Conv2d(512, out_ch, 3, padding=1)
382
+ self.side6 = nn.Conv2d(512, out_ch, 3, padding=1)
383
+
384
+ self.outconv = nn.Conv2d(6 * out_ch, out_ch, 1)
385
+
386
+ def forward(self, x):
387
+
388
+ hx = x
389
+
390
+ # stage 1
391
+ hx1 = self.stage1(hx)
392
+ hx = self.pool12(hx1)
393
+
394
+ # stage 2
395
+ hx2 = self.stage2(hx)
396
+ hx = self.pool23(hx2)
397
+
398
+ # stage 3
399
+ hx3 = self.stage3(hx)
400
+ hx = self.pool34(hx3)
401
+
402
+ # stage 4
403
+ hx4 = self.stage4(hx)
404
+ hx = self.pool45(hx4)
405
+
406
+ # stage 5
407
+ hx5 = self.stage5(hx)
408
+ hx = self.pool56(hx5)
409
+
410
+ # stage 6
411
+ hx6 = self.stage6(hx)
412
+ hx6up = _upsample_like(hx6, hx5)
413
+
414
+ # -------------------- decoder --------------------
415
+ hx5d = self.stage5d(torch.cat((hx6up, hx5), 1))
416
+ hx5dup = _upsample_like(hx5d, hx4)
417
+
418
+ hx4d = self.stage4d(torch.cat((hx5dup, hx4), 1))
419
+ hx4dup = _upsample_like(hx4d, hx3)
420
+
421
+ hx3d = self.stage3d(torch.cat((hx4dup, hx3), 1))
422
+ hx3dup = _upsample_like(hx3d, hx2)
423
+
424
+ hx2d = self.stage2d(torch.cat((hx3dup, hx2), 1))
425
+ hx2dup = _upsample_like(hx2d, hx1)
426
+
427
+ hx1d = self.stage1d(torch.cat((hx2dup, hx1), 1))
428
+
429
+ # side output
430
+ d1 = self.side1(hx1d)
431
+
432
+ d2 = self.side2(hx2d)
433
+ d2 = _upsample_like(d2, d1)
434
+
435
+ d3 = self.side3(hx3d)
436
+ d3 = _upsample_like(d3, d1)
437
+
438
+ d4 = self.side4(hx4d)
439
+ d4 = _upsample_like(d4, d1)
440
+
441
+ d5 = self.side5(hx5d)
442
+ d5 = _upsample_like(d5, d1)
443
+
444
+ d6 = self.side6(hx6)
445
+ d6 = _upsample_like(d6, d1)
446
+
447
+ d0 = self.outconv(torch.cat((d1, d2, d3, d4, d5, d6), 1))
448
+
449
+ """
450
+ del hx1, hx2, hx3, hx4, hx5, hx6
451
+ del hx5d, hx4d, hx3d, hx2d, hx1d
452
+ del hx6up, hx5dup, hx4dup, hx3dup, hx2dup
453
+ """
454
+
455
+ return d0, d1, d2, d3, d4, d5, d6
456
+
457
+
458
+ ### U^2-Net small ###
459
+ class U2NETP(nn.Module):
460
+ def __init__(self, in_ch=3, out_ch=1):
461
+ super(U2NETP, self).__init__()
462
+
463
+ self.stage1 = RSU7(in_ch, 16, 64)
464
+ self.pool12 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
465
+
466
+ self.stage2 = RSU6(64, 16, 64)
467
+ self.pool23 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
468
+
469
+ self.stage3 = RSU5(64, 16, 64)
470
+ self.pool34 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
471
+
472
+ self.stage4 = RSU4(64, 16, 64)
473
+ self.pool45 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
474
+
475
+ self.stage5 = RSU4F(64, 16, 64)
476
+ self.pool56 = nn.MaxPool2d(2, stride=2, ceil_mode=True)
477
+
478
+ self.stage6 = RSU4F(64, 16, 64)
479
+
480
+ # decoder
481
+ self.stage5d = RSU4F(128, 16, 64)
482
+ self.stage4d = RSU4(128, 16, 64)
483
+ self.stage3d = RSU5(128, 16, 64)
484
+ self.stage2d = RSU6(128, 16, 64)
485
+ self.stage1d = RSU7(128, 16, 64)
486
+
487
+ self.side1 = nn.Conv2d(64, out_ch, 3, padding=1)
488
+ self.side2 = nn.Conv2d(64, out_ch, 3, padding=1)
489
+ self.side3 = nn.Conv2d(64, out_ch, 3, padding=1)
490
+ self.side4 = nn.Conv2d(64, out_ch, 3, padding=1)
491
+ self.side5 = nn.Conv2d(64, out_ch, 3, padding=1)
492
+ self.side6 = nn.Conv2d(64, out_ch, 3, padding=1)
493
+
494
+ self.outconv = nn.Conv2d(6 * out_ch, out_ch, 1)
495
+
496
+ def forward(self, x):
497
+
498
+ hx = x
499
+
500
+ # stage 1
501
+ hx1 = self.stage1(hx)
502
+ hx = self.pool12(hx1)
503
+
504
+ # stage 2
505
+ hx2 = self.stage2(hx)
506
+ hx = self.pool23(hx2)
507
+
508
+ # stage 3
509
+ hx3 = self.stage3(hx)
510
+ hx = self.pool34(hx3)
511
+
512
+ # stage 4
513
+ hx4 = self.stage4(hx)
514
+ hx = self.pool45(hx4)
515
+
516
+ # stage 5
517
+ hx5 = self.stage5(hx)
518
+ hx = self.pool56(hx5)
519
+
520
+ # stage 6
521
+ hx6 = self.stage6(hx)
522
+ hx6up = _upsample_like(hx6, hx5)
523
+
524
+ # decoder
525
+ hx5d = self.stage5d(torch.cat((hx6up, hx5), 1))
526
+ hx5dup = _upsample_like(hx5d, hx4)
527
+
528
+ hx4d = self.stage4d(torch.cat((hx5dup, hx4), 1))
529
+ hx4dup = _upsample_like(hx4d, hx3)
530
+
531
+ hx3d = self.stage3d(torch.cat((hx4dup, hx3), 1))
532
+ hx3dup = _upsample_like(hx3d, hx2)
533
+
534
+ hx2d = self.stage2d(torch.cat((hx3dup, hx2), 1))
535
+ hx2dup = _upsample_like(hx2d, hx1)
536
+
537
+ hx1d = self.stage1d(torch.cat((hx2dup, hx1), 1))
538
+
539
+ # side output
540
+ d1 = self.side1(hx1d)
541
+
542
+ d2 = self.side2(hx2d)
543
+ d2 = _upsample_like(d2, d1)
544
+
545
+ d3 = self.side3(hx3d)
546
+ d3 = _upsample_like(d3, d1)
547
+
548
+ d4 = self.side4(hx4d)
549
+ d4 = _upsample_like(d4, d1)
550
+
551
+ d5 = self.side5(hx5d)
552
+ d5 = _upsample_like(d5, d1)
553
+
554
+ d6 = self.side6(hx6)
555
+ d6 = _upsample_like(d6, d1)
556
+
557
+ d0 = self.outconv(torch.cat((d1, d2, d3, d4, d5, d6), 1))
558
+
559
+ return d0, d1, d2, d3, d4, d5, d6
src/unet/predictor.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.unet.network import U2NET
2
+
3
+ import os
4
+ from PIL import Image
5
+ import argparse
6
+ import numpy as np
7
+
8
+ import torch
9
+ import torch.nn.functional as F
10
+ import torchvision.transforms as transforms
11
+
12
+ from collections import OrderedDict
13
+
14
+
15
+ def load_checkpoint(model, checkpoint_path):
16
+ if not os.path.exists(checkpoint_path):
17
+ print("----No checkpoints at given path----")
18
+ return
19
+ model_state_dict = torch.load(checkpoint_path, map_location=torch.device("cpu"))
20
+ new_state_dict = OrderedDict()
21
+ for k, v in model_state_dict.items():
22
+ name = k[7:] # remove `module.`
23
+ new_state_dict[name] = v
24
+
25
+ model.load_state_dict(new_state_dict)
26
+ print("----checkpoints loaded from path: {}----".format(checkpoint_path))
27
+ return model
28
+
29
+
30
+ def get_palette(num_cls):
31
+ """ Returns the color map for visualizing the segmentation mask.
32
+ Args:
33
+ num_cls: Number of classes
34
+ Returns:
35
+ The color map
36
+ """
37
+ n = num_cls
38
+ palette = [0] * (n * 3)
39
+ for j in range(0, n):
40
+ lab = j
41
+ palette[j * 3 + 0] = 0
42
+ palette[j * 3 + 1] = 0
43
+ palette[j * 3 + 2] = 0
44
+ i = 0
45
+ while lab:
46
+ palette[j * 3 + 0] |= (((lab >> 0) & 1) << (7 - i))
47
+ palette[j * 3 + 1] |= (((lab >> 1) & 1) << (7 - i))
48
+ palette[j * 3 + 2] |= (((lab >> 2) & 1) << (7 - i))
49
+ i += 1
50
+ lab >>= 3
51
+ return palette
52
+
53
+
54
+ class Normalize_image(object):
55
+ """Normalize given tensor into given mean and standard dev
56
+
57
+ Args:
58
+ mean (float): Desired mean to substract from tensors
59
+ std (float): Desired std to divide from tensors
60
+ """
61
+
62
+ def __init__(self, mean, std):
63
+ assert isinstance(mean, (float))
64
+ if isinstance(mean, float):
65
+ self.mean = mean
66
+
67
+ if isinstance(std, float):
68
+ self.std = std
69
+
70
+ self.normalize_1 = transforms.Normalize(self.mean, self.std)
71
+ self.normalize_3 = transforms.Normalize([self.mean] * 3, [self.std] * 3)
72
+ self.normalize_18 = transforms.Normalize([self.mean] * 18, [self.std] * 18)
73
+
74
+ def __call__(self, image_tensor):
75
+ if image_tensor.shape[0] == 1:
76
+ return self.normalize_1(image_tensor)
77
+
78
+ elif image_tensor.shape[0] == 3:
79
+ return self.normalize_3(image_tensor)
80
+
81
+ elif image_tensor.shape[0] == 18:
82
+ return self.normalize_18(image_tensor)
83
+
84
+ else:
85
+ assert "Please set proper channels! Normlization implemented only for 1, 3 and 18"
86
+
87
+
88
+ def apply_transform(img):
89
+ transforms_list = []
90
+ transforms_list += [transforms.ToTensor()]
91
+ transforms_list += [Normalize_image(0.5, 0.5)]
92
+ transform_rgb = transforms.Compose(transforms_list)
93
+ return transform_rgb(img)
94
+
95
+
96
+ def generate_mask(input_image, net, palette=None, device='cpu'):
97
+
98
+ if isinstance(input_image, np.ndarray):
99
+ input_image = Image.fromarray(input_image)
100
+
101
+ img = input_image
102
+ img_size = img.size
103
+ img = img.resize((768, 768), Image.BICUBIC)
104
+ image_tensor = apply_transform(img)
105
+ image_tensor = torch.unsqueeze(image_tensor, 0)
106
+
107
+ with torch.no_grad():
108
+ output_tensor = net(image_tensor.to(device))
109
+ output_tensor = F.log_softmax(output_tensor[0], dim=1)
110
+ output_tensor = torch.max(output_tensor, dim=1, keepdim=True)[1]
111
+ output_tensor = torch.squeeze(output_tensor, dim=0)
112
+ output_arr = output_tensor.cpu().numpy()
113
+
114
+ # Save final cloth segmentations
115
+ mask = output_arr[0].astype(np.uint8)
116
+
117
+ if not palette:
118
+ return mask
119
+
120
+ mask_image_palette = Image.fromarray(mask, mode='P')
121
+ mask_image_palette.putpalette(palette)
122
+ mask_image_palette = mask_image_palette.resize(img_size, Image.BICUBIC)
123
+ return mask, mask_image_palette
124
+
125
+
126
+ def load_seg_model(checkpoint_path, device='cpu'):
127
+ net = U2NET(in_ch=3, out_ch=4)
128
+ net = load_checkpoint(net, checkpoint_path)
129
+ net = net.to(device)
130
+ net = net.eval()
131
+
132
+ return net
133
+
134
+
135
+ def main(args):
136
+
137
+ device = 'cuda:0' if args.cuda else 'cpu'
138
+
139
+ # Create an instance of your model
140
+ model = load_seg_model(args.checkpoint_path, device=device)
141
+
142
+ palette = get_palette(4)
143
+
144
+ img = Image.open(args.image).convert('RGB')
145
+
146
+ mask, mask_image_palette = generate_mask(img, net=model, palette=palette, device=device)
147
+
148
+
149
+ if __name__ == '__main__':
150
+ parser = argparse.ArgumentParser(description='Help to set arguments for Cloth Segmentation.')
151
+ parser.add_argument('--image', type=str, help='Path to the input image')
152
+ parser.add_argument('--cuda', action='store_true', help='Enable CUDA (default: False)')
153
+ parser.add_argument('--checkpoint_path', type=str, default='../models/cloth_segm.pth', help='Path to the checkpoint file')
154
+ args = parser.parse_args()
155
+
156
+ args.image = '/pub/home/korostelev/data/diffusion/test/804a460e4bd0d666d51e84adc70f5490.jpg'
157
+ main(args)