Commit
•
e5765b1
1
Parent(s):
da856a8
Upload folder using huggingface_hub
Browse files- .gitattributes +1 -0
- README.md +19 -0
- cloths_segmentation/__init__.py +1 -0
- cloths_segmentation/__pycache__/__init__.cpython-310.pyc +0 -0
- cloths_segmentation/__pycache__/__init__.cpython-37.pyc +0 -0
- cloths_segmentation/__pycache__/pre_trained_models.cpython-310.pyc +0 -0
- cloths_segmentation/__pycache__/pre_trained_models.cpython-37.pyc +0 -0
- cloths_segmentation/configs/2020-10-29.yaml +122 -0
- cloths_segmentation/configs/2020-10-29a.yaml +124 -0
- cloths_segmentation/configs/2020-10-30.yaml +147 -0
- cloths_segmentation/dataloaders.py +50 -0
- cloths_segmentation/inference.py +161 -0
- cloths_segmentation/metrics.py +18 -0
- cloths_segmentation/pre_trained_models.py +23 -0
- cloths_segmentation/train.py +180 -0
- cloths_segmentation/utils.py +22 -0
- rb.py +34 -0
- semgent_from_folder.py +105 -0
- test.jpg +0 -0
- test.png +3 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
test.png filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Clothes Segmentation
|
2 |
+
This is my implementation of [this project](https://github.com/ternaus/cloths_segmentation)!
|
3 |
+
|
4 |
+
## Dependencies
|
5 |
+
- python >= 3.6
|
6 |
+
- [pytorch](https://pytorch.org/) >= 1.2
|
7 |
+
- opencv
|
8 |
+
- matplotlib
|
9 |
+
- albumentations, iglovikov_helper_functions, pytorch_lightning, pytorch_toolbelt, segmentation-models-pytorch, tqdm, wandb
|
10 |
+
|
11 |
+
## Installation
|
12 |
+
1. Download & install cuda 10.2 toolkit [here](https://developer.nvidia.com/cuda-10.2-download-archive?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1804&target_type=debnetwork)
|
13 |
+
2. Download & install anaconda python 3.7 version
|
14 |
+
3. Install Dependencies
|
15 |
+
4. Run `main.py`
|
16 |
+
|
17 |
+
## A example
|
18 |
+
<a href="url"><img src="test.jpg" align="left" style="width=50%" ></a>
|
19 |
+
<a href="url"><img src="test.png" align="left" style="width=50%" ></a>
|
cloths_segmentation/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
__version__ = "0.0.2"
|
cloths_segmentation/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (233 Bytes). View file
|
|
cloths_segmentation/__pycache__/__init__.cpython-37.pyc
ADDED
Binary file (165 Bytes). View file
|
|
cloths_segmentation/__pycache__/pre_trained_models.cpython-310.pyc
ADDED
Binary file (1.08 kB). View file
|
|
cloths_segmentation/__pycache__/pre_trained_models.cpython-37.pyc
ADDED
Binary file (1 kB). View file
|
|
cloths_segmentation/configs/2020-10-29.yaml
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
seed: 1984
|
3 |
+
|
4 |
+
num_workers: 4
|
5 |
+
experiment_name: "2020-10-29"
|
6 |
+
|
7 |
+
val_split: 0.2
|
8 |
+
|
9 |
+
model:
|
10 |
+
type: segmentation_models_pytorch.Unet
|
11 |
+
encoder_name: timm-efficientnet-b3
|
12 |
+
classes: 1
|
13 |
+
encoder_weights: noisy-student
|
14 |
+
|
15 |
+
trainer:
|
16 |
+
type: pytorch_lightning.Trainer
|
17 |
+
gpus: 4
|
18 |
+
max_epochs: 30
|
19 |
+
distributed_backend: ddp
|
20 |
+
progress_bar_refresh_rate: 1
|
21 |
+
benchmark: True
|
22 |
+
precision: 16
|
23 |
+
gradient_clip_val: 5.0
|
24 |
+
num_sanity_val_steps: 2
|
25 |
+
sync_batchnorm: True
|
26 |
+
|
27 |
+
|
28 |
+
scheduler:
|
29 |
+
type: torch.optim.lr_scheduler.CosineAnnealingWarmRestarts
|
30 |
+
T_0: 10
|
31 |
+
T_mult: 2
|
32 |
+
|
33 |
+
train_parameters:
|
34 |
+
batch_size: 8
|
35 |
+
|
36 |
+
checkpoint_callback:
|
37 |
+
type: pytorch_lightning.callbacks.ModelCheckpoint
|
38 |
+
filepath: "2020-10-29"
|
39 |
+
monitor: val_iou
|
40 |
+
verbose: True
|
41 |
+
mode: max
|
42 |
+
save_top_k: -1
|
43 |
+
|
44 |
+
val_parameters:
|
45 |
+
batch_size: 2
|
46 |
+
|
47 |
+
optimizer:
|
48 |
+
type: adamp.AdamP
|
49 |
+
lr: 0.0001
|
50 |
+
|
51 |
+
|
52 |
+
train_aug:
|
53 |
+
transform:
|
54 |
+
__class_fullname__: albumentations.core.composition.Compose
|
55 |
+
bbox_params: null
|
56 |
+
keypoint_params: null
|
57 |
+
p: 1
|
58 |
+
transforms:
|
59 |
+
- __class_fullname__: albumentations.augmentations.transforms.LongestMaxSize
|
60 |
+
always_apply: False
|
61 |
+
max_size: 800
|
62 |
+
p: 1
|
63 |
+
- __class_fullname__: albumentations.augmentations.transforms.PadIfNeeded
|
64 |
+
always_apply: False
|
65 |
+
min_height: 800
|
66 |
+
min_width: 800
|
67 |
+
border_mode: 0 # cv2.BORDER_CONSTANT
|
68 |
+
value: 0
|
69 |
+
mask_value: 0
|
70 |
+
p: 1
|
71 |
+
- __class_fullname__: albumentations.augmentations.transforms.RandomCrop
|
72 |
+
always_apply: False
|
73 |
+
height: 512
|
74 |
+
width: 512
|
75 |
+
p: 1
|
76 |
+
- __class_fullname__: albumentations.augmentations.transforms.HorizontalFlip
|
77 |
+
always_apply: False
|
78 |
+
p: 0.5
|
79 |
+
- __class_fullname__: albumentations.augmentations.transforms.Normalize
|
80 |
+
always_apply: false
|
81 |
+
max_pixel_value: 255.0
|
82 |
+
mean:
|
83 |
+
- 0.485
|
84 |
+
- 0.456
|
85 |
+
- 0.406
|
86 |
+
p: 1
|
87 |
+
std:
|
88 |
+
- 0.229
|
89 |
+
- 0.224
|
90 |
+
- 0.225
|
91 |
+
|
92 |
+
val_aug:
|
93 |
+
transform:
|
94 |
+
__class_fullname__: albumentations.core.composition.Compose
|
95 |
+
bbox_params: null
|
96 |
+
keypoint_params: null
|
97 |
+
p: 1
|
98 |
+
transforms:
|
99 |
+
- __class_fullname__: albumentations.augmentations.transforms.LongestMaxSize
|
100 |
+
always_apply: False
|
101 |
+
max_size: 800
|
102 |
+
p: 1
|
103 |
+
- __class_fullname__: albumentations.augmentations.transforms.PadIfNeeded
|
104 |
+
always_apply: False
|
105 |
+
min_height: 800
|
106 |
+
min_width: 800
|
107 |
+
border_mode: 0 # cv2.BORDER_CONSTANT
|
108 |
+
value: 0
|
109 |
+
mask_value: 0
|
110 |
+
p: 1
|
111 |
+
- __class_fullname__: albumentations.augmentations.transforms.Normalize
|
112 |
+
always_apply: false
|
113 |
+
max_pixel_value: 255.0
|
114 |
+
mean:
|
115 |
+
- 0.485
|
116 |
+
- 0.456
|
117 |
+
- 0.406
|
118 |
+
p: 1
|
119 |
+
std:
|
120 |
+
- 0.229
|
121 |
+
- 0.224
|
122 |
+
- 0.225
|
cloths_segmentation/configs/2020-10-29a.yaml
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
seed: 1984
|
3 |
+
|
4 |
+
num_workers: 4
|
5 |
+
experiment_name: "2020-10-29a"
|
6 |
+
|
7 |
+
val_split: 0.1
|
8 |
+
|
9 |
+
resume_from_checkpoint: 2020-10-29/epoch=4.ckpt
|
10 |
+
|
11 |
+
model:
|
12 |
+
type: segmentation_models_pytorch.Unet
|
13 |
+
encoder_name: timm-efficientnet-b3
|
14 |
+
classes: 1
|
15 |
+
encoder_weights: noisy-student
|
16 |
+
|
17 |
+
trainer:
|
18 |
+
type: pytorch_lightning.Trainer
|
19 |
+
gpus: 4
|
20 |
+
max_epochs: 30
|
21 |
+
distributed_backend: ddp
|
22 |
+
progress_bar_refresh_rate: 1
|
23 |
+
benchmark: True
|
24 |
+
precision: 16
|
25 |
+
gradient_clip_val: 5.0
|
26 |
+
num_sanity_val_steps: 2
|
27 |
+
sync_batchnorm: True
|
28 |
+
|
29 |
+
|
30 |
+
scheduler:
|
31 |
+
type: torch.optim.lr_scheduler.CosineAnnealingWarmRestarts
|
32 |
+
T_0: 10
|
33 |
+
T_mult: 2
|
34 |
+
|
35 |
+
train_parameters:
|
36 |
+
batch_size: 8
|
37 |
+
|
38 |
+
checkpoint_callback:
|
39 |
+
type: pytorch_lightning.callbacks.ModelCheckpoint
|
40 |
+
filepath: "2020-10-29a"
|
41 |
+
monitor: val_iou
|
42 |
+
verbose: True
|
43 |
+
mode: max
|
44 |
+
save_top_k: -1
|
45 |
+
|
46 |
+
val_parameters:
|
47 |
+
batch_size: 2
|
48 |
+
|
49 |
+
optimizer:
|
50 |
+
type: adamp.AdamP
|
51 |
+
lr: 0.0001
|
52 |
+
|
53 |
+
|
54 |
+
train_aug:
|
55 |
+
transform:
|
56 |
+
__class_fullname__: albumentations.core.composition.Compose
|
57 |
+
bbox_params: null
|
58 |
+
keypoint_params: null
|
59 |
+
p: 1
|
60 |
+
transforms:
|
61 |
+
- __class_fullname__: albumentations.augmentations.transforms.LongestMaxSize
|
62 |
+
always_apply: False
|
63 |
+
max_size: 800
|
64 |
+
p: 1
|
65 |
+
- __class_fullname__: albumentations.augmentations.transforms.PadIfNeeded
|
66 |
+
always_apply: False
|
67 |
+
min_height: 800
|
68 |
+
min_width: 800
|
69 |
+
border_mode: 0 # cv2.BORDER_CONSTANT
|
70 |
+
value: 0
|
71 |
+
mask_value: 0
|
72 |
+
p: 1
|
73 |
+
- __class_fullname__: albumentations.augmentations.transforms.RandomCrop
|
74 |
+
always_apply: False
|
75 |
+
height: 512
|
76 |
+
width: 512
|
77 |
+
p: 1
|
78 |
+
- __class_fullname__: albumentations.augmentations.transforms.HorizontalFlip
|
79 |
+
always_apply: False
|
80 |
+
p: 0.5
|
81 |
+
- __class_fullname__: albumentations.augmentations.transforms.Normalize
|
82 |
+
always_apply: false
|
83 |
+
max_pixel_value: 255.0
|
84 |
+
mean:
|
85 |
+
- 0.485
|
86 |
+
- 0.456
|
87 |
+
- 0.406
|
88 |
+
p: 1
|
89 |
+
std:
|
90 |
+
- 0.229
|
91 |
+
- 0.224
|
92 |
+
- 0.225
|
93 |
+
|
94 |
+
val_aug:
|
95 |
+
transform:
|
96 |
+
__class_fullname__: albumentations.core.composition.Compose
|
97 |
+
bbox_params: null
|
98 |
+
keypoint_params: null
|
99 |
+
p: 1
|
100 |
+
transforms:
|
101 |
+
- __class_fullname__: albumentations.augmentations.transforms.LongestMaxSize
|
102 |
+
always_apply: False
|
103 |
+
max_size: 800
|
104 |
+
p: 1
|
105 |
+
- __class_fullname__: albumentations.augmentations.transforms.PadIfNeeded
|
106 |
+
always_apply: False
|
107 |
+
min_height: 800
|
108 |
+
min_width: 800
|
109 |
+
border_mode: 0 # cv2.BORDER_CONSTANT
|
110 |
+
value: 0
|
111 |
+
mask_value: 0
|
112 |
+
p: 1
|
113 |
+
- __class_fullname__: albumentations.augmentations.transforms.Normalize
|
114 |
+
always_apply: false
|
115 |
+
max_pixel_value: 255.0
|
116 |
+
mean:
|
117 |
+
- 0.485
|
118 |
+
- 0.456
|
119 |
+
- 0.406
|
120 |
+
p: 1
|
121 |
+
std:
|
122 |
+
- 0.229
|
123 |
+
- 0.224
|
124 |
+
- 0.225
|
cloths_segmentation/configs/2020-10-30.yaml
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
seed: 1984
|
3 |
+
|
4 |
+
num_workers: 4
|
5 |
+
experiment_name: "2020-10-30"
|
6 |
+
|
7 |
+
val_split: 0.1
|
8 |
+
|
9 |
+
model:
|
10 |
+
type: segmentation_models_pytorch.Unet
|
11 |
+
encoder_name: timm-efficientnet-b3
|
12 |
+
classes: 1
|
13 |
+
encoder_weights: noisy-student
|
14 |
+
|
15 |
+
trainer:
|
16 |
+
type: pytorch_lightning.Trainer
|
17 |
+
gpus: 4
|
18 |
+
max_epochs: 70
|
19 |
+
distributed_backend: ddp
|
20 |
+
progress_bar_refresh_rate: 1
|
21 |
+
benchmark: True
|
22 |
+
precision: 16
|
23 |
+
gradient_clip_val: 5.0
|
24 |
+
num_sanity_val_steps: 2
|
25 |
+
sync_batchnorm: True
|
26 |
+
# resume_from_checkpoint: 2020-10-30/epoch=67.ckpt
|
27 |
+
|
28 |
+
|
29 |
+
scheduler:
|
30 |
+
type: torch.optim.lr_scheduler.CosineAnnealingWarmRestarts
|
31 |
+
T_0: 10
|
32 |
+
T_mult: 2
|
33 |
+
|
34 |
+
train_parameters:
|
35 |
+
batch_size: 8
|
36 |
+
|
37 |
+
checkpoint_callback:
|
38 |
+
type: pytorch_lightning.callbacks.ModelCheckpoint
|
39 |
+
filepath: "2020-10-30"
|
40 |
+
monitor: val_iou
|
41 |
+
verbose: True
|
42 |
+
mode: max
|
43 |
+
save_top_k: -1
|
44 |
+
|
45 |
+
val_parameters:
|
46 |
+
batch_size: 2
|
47 |
+
|
48 |
+
optimizer:
|
49 |
+
type: adamp.AdamP
|
50 |
+
lr: 0.0001
|
51 |
+
|
52 |
+
|
53 |
+
train_aug:
|
54 |
+
transform:
|
55 |
+
__class_fullname__: albumentations.core.composition.Compose
|
56 |
+
bbox_params: null
|
57 |
+
keypoint_params: null
|
58 |
+
p: 1
|
59 |
+
transforms:
|
60 |
+
- __class_fullname__: albumentations.augmentations.transforms.LongestMaxSize
|
61 |
+
always_apply: False
|
62 |
+
max_size: 800
|
63 |
+
p: 1
|
64 |
+
- __class_fullname__: albumentations.augmentations.transforms.PadIfNeeded
|
65 |
+
always_apply: False
|
66 |
+
min_height: 800
|
67 |
+
min_width: 800
|
68 |
+
border_mode: 0 # cv2.BORDER_CONSTANT
|
69 |
+
value: 0
|
70 |
+
mask_value: 0
|
71 |
+
p: 1
|
72 |
+
- __class_fullname__: albumentations.augmentations.transforms.RandomCrop
|
73 |
+
always_apply: False
|
74 |
+
height: 512
|
75 |
+
width: 512
|
76 |
+
p: 1
|
77 |
+
- __class_fullname__: albumentations.augmentations.transforms.HorizontalFlip
|
78 |
+
always_apply: False
|
79 |
+
p: 0.5
|
80 |
+
- __class_fullname__: albumentations.augmentations.transforms.Normalize
|
81 |
+
always_apply: false
|
82 |
+
max_pixel_value: 255.0
|
83 |
+
mean:
|
84 |
+
- 0.485
|
85 |
+
- 0.456
|
86 |
+
- 0.406
|
87 |
+
p: 1
|
88 |
+
std:
|
89 |
+
- 0.229
|
90 |
+
- 0.224
|
91 |
+
- 0.225
|
92 |
+
|
93 |
+
val_aug:
|
94 |
+
transform:
|
95 |
+
__class_fullname__: albumentations.core.composition.Compose
|
96 |
+
bbox_params: null
|
97 |
+
keypoint_params: null
|
98 |
+
p: 1
|
99 |
+
transforms:
|
100 |
+
- __class_fullname__: albumentations.augmentations.transforms.LongestMaxSize
|
101 |
+
always_apply: False
|
102 |
+
max_size: 800
|
103 |
+
p: 1
|
104 |
+
- __class_fullname__: albumentations.augmentations.transforms.PadIfNeeded
|
105 |
+
always_apply: False
|
106 |
+
min_height: 800
|
107 |
+
min_width: 800
|
108 |
+
border_mode: 0 # cv2.BORDER_CONSTANT
|
109 |
+
value: 0
|
110 |
+
mask_value: 0
|
111 |
+
p: 1
|
112 |
+
- __class_fullname__: albumentations.augmentations.transforms.Normalize
|
113 |
+
always_apply: false
|
114 |
+
max_pixel_value: 255.0
|
115 |
+
mean:
|
116 |
+
- 0.485
|
117 |
+
- 0.456
|
118 |
+
- 0.406
|
119 |
+
p: 1
|
120 |
+
std:
|
121 |
+
- 0.229
|
122 |
+
- 0.224
|
123 |
+
- 0.225
|
124 |
+
|
125 |
+
test_aug:
|
126 |
+
transform:
|
127 |
+
__class_fullname__: albumentations.core.composition.Compose
|
128 |
+
bbox_params: null
|
129 |
+
keypoint_params: null
|
130 |
+
p: 1
|
131 |
+
transforms:
|
132 |
+
- __class_fullname__: albumentations.augmentations.transforms.LongestMaxSize
|
133 |
+
always_apply: False
|
134 |
+
max_size: 800
|
135 |
+
p: 1
|
136 |
+
- __class_fullname__: albumentations.augmentations.transforms.Normalize
|
137 |
+
always_apply: false
|
138 |
+
max_pixel_value: 255.0
|
139 |
+
mean:
|
140 |
+
- 0.485
|
141 |
+
- 0.456
|
142 |
+
- 0.406
|
143 |
+
p: 1
|
144 |
+
std:
|
145 |
+
- 0.229
|
146 |
+
- 0.224
|
147 |
+
- 0.225
|
cloths_segmentation/dataloaders.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
from typing import List, Dict, Any, Tuple
|
3 |
+
|
4 |
+
import albumentations as albu
|
5 |
+
import numpy as np
|
6 |
+
import torch
|
7 |
+
from iglovikov_helper_functions.utils.image_utils import load_rgb, load_grayscale
|
8 |
+
from pytorch_toolbelt.utils.torch_utils import tensor_from_rgb_image
|
9 |
+
from torch.utils.data import Dataset
|
10 |
+
|
11 |
+
|
12 |
+
class SegmentationDataset(Dataset):
|
13 |
+
def __init__(
|
14 |
+
self,
|
15 |
+
samples: List[Tuple[Path, Path]],
|
16 |
+
transform: albu.Compose,
|
17 |
+
length: int = None,
|
18 |
+
) -> None:
|
19 |
+
self.samples = samples
|
20 |
+
self.transform = transform
|
21 |
+
|
22 |
+
if length is None:
|
23 |
+
self.length = len(self.samples)
|
24 |
+
else:
|
25 |
+
self.length = length
|
26 |
+
|
27 |
+
def __len__(self) -> int:
|
28 |
+
return self.length
|
29 |
+
|
30 |
+
def __getitem__(self, idx: int) -> Dict[str, Any]:
|
31 |
+
idx = idx % len(self.samples)
|
32 |
+
|
33 |
+
image_path, mask_path = self.samples[idx]
|
34 |
+
|
35 |
+
image = load_rgb(image_path, lib="cv2")
|
36 |
+
mask = load_grayscale(mask_path)
|
37 |
+
|
38 |
+
# apply augmentations
|
39 |
+
sample = self.transform(image=image, mask=mask)
|
40 |
+
image, mask = sample["image"], sample["mask"]
|
41 |
+
|
42 |
+
mask = (mask > 0).astype(np.uint8)
|
43 |
+
|
44 |
+
mask = torch.from_numpy(mask)
|
45 |
+
|
46 |
+
return {
|
47 |
+
"image_id": image_path.stem,
|
48 |
+
"features": tensor_from_rgb_image(image),
|
49 |
+
"masks": torch.unsqueeze(mask, 0).float(),
|
50 |
+
}
|
cloths_segmentation/inference.py
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
from pathlib import Path
|
3 |
+
from typing import Dict, List, Optional, Any
|
4 |
+
|
5 |
+
import albumentations as albu
|
6 |
+
import cv2
|
7 |
+
import numpy as np
|
8 |
+
import torch
|
9 |
+
import torch.nn.parallel
|
10 |
+
import torch.utils.data
|
11 |
+
import torch.utils.data.distributed
|
12 |
+
import yaml
|
13 |
+
from albumentations.core.serialization import from_dict
|
14 |
+
from iglovikov_helper_functions.config_parsing.utils import object_from_dict
|
15 |
+
from iglovikov_helper_functions.dl.pytorch.utils import state_dict_from_disk, tensor_from_rgb_image
|
16 |
+
from iglovikov_helper_functions.utils.image_utils import load_rgb, pad_to_size, unpad_from_size
|
17 |
+
from torch.utils.data import Dataset
|
18 |
+
from torch.utils.data.distributed import DistributedSampler
|
19 |
+
from tqdm import tqdm
|
20 |
+
|
21 |
+
|
22 |
+
def get_args():
|
23 |
+
parser = argparse.ArgumentParser()
|
24 |
+
arg = parser.add_argument
|
25 |
+
arg("-i", "--input_path", type=Path, help="Path with images.", required=True)
|
26 |
+
arg("-c", "--config_path", type=Path, help="Path to config.", required=True)
|
27 |
+
arg("-o", "--output_path", type=Path, help="Path to save masks.", required=True)
|
28 |
+
arg("-b", "--batch_size", type=int, help="batch_size", default=1)
|
29 |
+
arg("-j", "--num_workers", type=int, help="num_workers", default=12)
|
30 |
+
arg("-w", "--weight_path", type=str, help="Path to weights.", required=True)
|
31 |
+
arg("--world_size", default=-1, type=int, help="number of nodes for distributed training")
|
32 |
+
arg("--local_rank", default=-1, type=int, help="node rank for distributed training")
|
33 |
+
arg("--fp16", action="store_true", help="Use fp6")
|
34 |
+
return parser.parse_args()
|
35 |
+
|
36 |
+
|
37 |
+
class InferenceDataset(Dataset):
|
38 |
+
def __init__(self, file_paths: List[Path], transform: albu.Compose) -> None:
|
39 |
+
self.file_paths = file_paths
|
40 |
+
self.transform = transform
|
41 |
+
|
42 |
+
def __len__(self) -> int:
|
43 |
+
return len(self.file_paths)
|
44 |
+
|
45 |
+
def __getitem__(self, idx: int) -> Optional[Dict[str, Any]]:
|
46 |
+
image_path = self.file_paths[idx]
|
47 |
+
|
48 |
+
image = load_rgb(image_path)
|
49 |
+
height, width = image.shape[:2]
|
50 |
+
|
51 |
+
image = self.transform(image=image)["image"]
|
52 |
+
pad_dict = pad_to_size((max(image.shape[:2]), max(image.shape[:2])), image)
|
53 |
+
|
54 |
+
return {
|
55 |
+
"torched_image": tensor_from_rgb_image(pad_dict["image"]),
|
56 |
+
"image_path": str(image_path),
|
57 |
+
"pads": pad_dict["pads"],
|
58 |
+
"original_width": width,
|
59 |
+
"original_height": height,
|
60 |
+
}
|
61 |
+
|
62 |
+
|
63 |
+
def main():
|
64 |
+
args = get_args()
|
65 |
+
torch.distributed.init_process_group(backend="nccl")
|
66 |
+
|
67 |
+
with open(args.config_path) as f:
|
68 |
+
hparams = yaml.load(f, Loader=yaml.SafeLoader)
|
69 |
+
|
70 |
+
hparams.update(
|
71 |
+
{
|
72 |
+
"local_rank": args.local_rank,
|
73 |
+
"fp16": args.fp16,
|
74 |
+
}
|
75 |
+
)
|
76 |
+
|
77 |
+
output_mask_path = args.output_path
|
78 |
+
output_mask_path.mkdir(parents=True, exist_ok=True)
|
79 |
+
hparams["output_mask_path"] = output_mask_path
|
80 |
+
|
81 |
+
device = torch.device("cuda", args.local_rank)
|
82 |
+
|
83 |
+
model = object_from_dict(hparams["model"])
|
84 |
+
model = model.to(device)
|
85 |
+
|
86 |
+
if args.fp16:
|
87 |
+
model = model.half()
|
88 |
+
|
89 |
+
corrections: Dict[str, str] = {"model.": ""}
|
90 |
+
state_dict = state_dict_from_disk(file_path=args.weight_path, rename_in_layers=corrections)
|
91 |
+
model.load_state_dict(state_dict)
|
92 |
+
|
93 |
+
model = torch.nn.parallel.DistributedDataParallel(
|
94 |
+
model, device_ids=[args.local_rank], output_device=args.local_rank
|
95 |
+
)
|
96 |
+
|
97 |
+
file_paths = []
|
98 |
+
|
99 |
+
for regexp in ["*.jpg", "*.png", "*.jpeg", "*.JPG"]:
|
100 |
+
file_paths += sorted([x for x in tqdm(args.input_path.rglob(regexp))])
|
101 |
+
|
102 |
+
# Filter file paths for which we already have predictions
|
103 |
+
file_paths = [x for x in file_paths if not (args.output_path / x.parent.name / f"{x.stem}.png").exists()]
|
104 |
+
|
105 |
+
dataset = InferenceDataset(file_paths, transform=from_dict(hparams["test_aug"]))
|
106 |
+
|
107 |
+
sampler = DistributedSampler(dataset, shuffle=False)
|
108 |
+
|
109 |
+
dataloader = torch.utils.data.DataLoader(
|
110 |
+
dataset,
|
111 |
+
batch_size=args.batch_size,
|
112 |
+
num_workers=args.num_workers,
|
113 |
+
pin_memory=True,
|
114 |
+
shuffle=False,
|
115 |
+
drop_last=False,
|
116 |
+
sampler=sampler,
|
117 |
+
)
|
118 |
+
|
119 |
+
predict(dataloader, model, hparams, device)
|
120 |
+
|
121 |
+
|
122 |
+
def predict(dataloader, model, hparams, device):
|
123 |
+
model.eval()
|
124 |
+
|
125 |
+
if hparams["local_rank"] == 0:
|
126 |
+
loader = tqdm(dataloader)
|
127 |
+
else:
|
128 |
+
loader = dataloader
|
129 |
+
|
130 |
+
with torch.no_grad():
|
131 |
+
for batch in loader:
|
132 |
+
torched_images = batch["torched_image"] # images that are rescaled and padded
|
133 |
+
|
134 |
+
if hparams["fp16"]:
|
135 |
+
torched_images = torched_images.half()
|
136 |
+
|
137 |
+
image_paths = batch["image_path"]
|
138 |
+
pads = batch["pads"]
|
139 |
+
heights = batch["original_height"]
|
140 |
+
widths = batch["original_width"]
|
141 |
+
|
142 |
+
batch_size = torched_images.shape[0]
|
143 |
+
|
144 |
+
predictions = model(torched_images.to(device))
|
145 |
+
|
146 |
+
for batch_id in range(batch_size):
|
147 |
+
file_id = Path(image_paths[batch_id]).stem
|
148 |
+
folder_name = Path(image_paths[batch_id]).parent.name
|
149 |
+
|
150 |
+
mask = (predictions[batch_id][0].cpu().numpy() > 0).astype(np.uint8) * 255
|
151 |
+
mask = unpad_from_size(pads, image=mask)["image"]
|
152 |
+
mask = cv2.resize(
|
153 |
+
mask, (widths[batch_id].item(), heights[batch_id].item()), interpolation=cv2.INTER_NEAREST
|
154 |
+
)
|
155 |
+
|
156 |
+
(hparams["output_mask_path"] / folder_name).mkdir(exist_ok=True, parents=True)
|
157 |
+
cv2.imwrite(str(hparams["output_mask_path"] / folder_name / f"{file_id}.png"), mask)
|
158 |
+
|
159 |
+
|
160 |
+
if __name__ == "__main__":
|
161 |
+
main()
|
cloths_segmentation/metrics.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
|
3 |
+
EPSILON = 1e-15
|
4 |
+
|
5 |
+
|
6 |
+
def binary_mean_iou(logits: torch.Tensor, targets: torch.Tensor) -> torch.Tensor:
|
7 |
+
output = (logits > 0).int()
|
8 |
+
|
9 |
+
if output.shape != targets.shape:
|
10 |
+
targets = torch.squeeze(targets, 1)
|
11 |
+
|
12 |
+
intersection = (targets * output).sum()
|
13 |
+
|
14 |
+
union = targets.sum() + output.sum() - intersection
|
15 |
+
|
16 |
+
result = (intersection + EPSILON) / (union + EPSILON)
|
17 |
+
|
18 |
+
return result
|
cloths_segmentation/pre_trained_models.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from collections import namedtuple
|
2 |
+
from torch import nn
|
3 |
+
from torch.utils import model_zoo
|
4 |
+
from iglovikov_helper_functions.dl.pytorch.utils import rename_layers
|
5 |
+
|
6 |
+
from segmentation_models_pytorch import Unet
|
7 |
+
|
8 |
+
model = namedtuple("model", ["url", "model"])
|
9 |
+
|
10 |
+
models = {
|
11 |
+
"Unet_2020-10-30": model(
|
12 |
+
url="https://github.com/ternaus/cloths_segmentation/releases/download/0.0.1/weights.zip",
|
13 |
+
model=Unet(encoder_name="timm-efficientnet-b3", classes=1, encoder_weights=None),
|
14 |
+
)
|
15 |
+
}
|
16 |
+
|
17 |
+
|
18 |
+
def create_model(model_name: str) -> nn.Module:
|
19 |
+
model = models[model_name].model
|
20 |
+
state_dict = model_zoo.load_url(models[model_name].url, progress=True, map_location="cpu")["state_dict"]
|
21 |
+
state_dict = rename_layers(state_dict, {"model.": ""})
|
22 |
+
model.load_state_dict(state_dict)
|
23 |
+
return model
|
cloths_segmentation/train.py
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
import os
|
3 |
+
from pathlib import Path
|
4 |
+
from typing import Dict
|
5 |
+
|
6 |
+
import pytorch_lightning as pl
|
7 |
+
import torch
|
8 |
+
import yaml
|
9 |
+
from albumentations.core.serialization import from_dict
|
10 |
+
from iglovikov_helper_functions.config_parsing.utils import object_from_dict
|
11 |
+
from iglovikov_helper_functions.dl.pytorch.lightning import find_average
|
12 |
+
from iglovikov_helper_functions.dl.pytorch.utils import state_dict_from_disk
|
13 |
+
from pytorch_lightning.loggers import WandbLogger
|
14 |
+
from pytorch_toolbelt.losses import JaccardLoss, BinaryFocalLoss
|
15 |
+
from torch.utils.data import DataLoader
|
16 |
+
|
17 |
+
from cloths_segmentation.dataloaders import SegmentationDataset
|
18 |
+
from cloths_segmentation.metrics import binary_mean_iou
|
19 |
+
from cloths_segmentation.utils import get_samples
|
20 |
+
|
21 |
+
image_path = Path(os.environ["IMAGE_PATH"])
|
22 |
+
mask_path = Path(os.environ["MASK_PATH"])
|
23 |
+
|
24 |
+
|
25 |
+
def get_args():
|
26 |
+
parser = argparse.ArgumentParser()
|
27 |
+
arg = parser.add_argument
|
28 |
+
arg("-c", "--config_path", type=Path, help="Path to the config.", required=True)
|
29 |
+
return parser.parse_args()
|
30 |
+
|
31 |
+
|
32 |
+
class SegmentPeople(pl.LightningModule):
|
33 |
+
def __init__(self, hparams):
|
34 |
+
super().__init__()
|
35 |
+
self.hparams = hparams
|
36 |
+
|
37 |
+
self.model = object_from_dict(self.hparams["model"])
|
38 |
+
if "resume_from_checkpoint" in self.hparams:
|
39 |
+
corrections: Dict[str, str] = {"model.": ""}
|
40 |
+
|
41 |
+
state_dict = state_dict_from_disk(
|
42 |
+
file_path=self.hparams["resume_from_checkpoint"],
|
43 |
+
rename_in_layers=corrections,
|
44 |
+
)
|
45 |
+
self.model.load_state_dict(state_dict)
|
46 |
+
|
47 |
+
self.losses = [
|
48 |
+
("jaccard", 0.1, JaccardLoss(mode="binary", from_logits=True)),
|
49 |
+
("focal", 0.9, BinaryFocalLoss()),
|
50 |
+
]
|
51 |
+
|
52 |
+
def forward(self, batch: torch.Tensor) -> torch.Tensor: # type: ignore
|
53 |
+
return self.model(batch)
|
54 |
+
|
55 |
+
def setup(self, stage=0):
|
56 |
+
samples = get_samples(image_path, mask_path)
|
57 |
+
|
58 |
+
num_train = int((1 - self.hparams["val_split"]) * len(samples))
|
59 |
+
|
60 |
+
self.train_samples = samples[:num_train]
|
61 |
+
self.val_samples = samples[num_train:]
|
62 |
+
|
63 |
+
print("Len train samples = ", len(self.train_samples))
|
64 |
+
print("Len val samples = ", len(self.val_samples))
|
65 |
+
|
66 |
+
def train_dataloader(self):
|
67 |
+
train_aug = from_dict(self.hparams["train_aug"])
|
68 |
+
|
69 |
+
if "epoch_length" not in self.hparams["train_parameters"]:
|
70 |
+
epoch_length = None
|
71 |
+
else:
|
72 |
+
epoch_length = self.hparams["train_parameters"]["epoch_length"]
|
73 |
+
|
74 |
+
result = DataLoader(
|
75 |
+
SegmentationDataset(self.train_samples, train_aug, epoch_length),
|
76 |
+
batch_size=self.hparams["train_parameters"]["batch_size"],
|
77 |
+
num_workers=self.hparams["num_workers"],
|
78 |
+
shuffle=True,
|
79 |
+
pin_memory=True,
|
80 |
+
drop_last=True,
|
81 |
+
)
|
82 |
+
|
83 |
+
print("Train dataloader = ", len(result))
|
84 |
+
return result
|
85 |
+
|
86 |
+
def val_dataloader(self):
|
87 |
+
val_aug = from_dict(self.hparams["val_aug"])
|
88 |
+
|
89 |
+
result = DataLoader(
|
90 |
+
SegmentationDataset(self.val_samples, val_aug, length=None),
|
91 |
+
batch_size=self.hparams["val_parameters"]["batch_size"],
|
92 |
+
num_workers=self.hparams["num_workers"],
|
93 |
+
shuffle=False,
|
94 |
+
pin_memory=True,
|
95 |
+
drop_last=False,
|
96 |
+
)
|
97 |
+
|
98 |
+
print("Val dataloader = ", len(result))
|
99 |
+
|
100 |
+
return result
|
101 |
+
|
102 |
+
def configure_optimizers(self):
|
103 |
+
optimizer = object_from_dict(
|
104 |
+
self.hparams["optimizer"],
|
105 |
+
params=[x for x in self.model.parameters() if x.requires_grad],
|
106 |
+
)
|
107 |
+
|
108 |
+
scheduler = object_from_dict(self.hparams["scheduler"], optimizer=optimizer)
|
109 |
+
self.optimizers = [optimizer]
|
110 |
+
|
111 |
+
return self.optimizers, [scheduler]
|
112 |
+
|
113 |
+
def training_step(self, batch, batch_idx):
|
114 |
+
features = batch["features"]
|
115 |
+
masks = batch["masks"]
|
116 |
+
|
117 |
+
logits = self.forward(features)
|
118 |
+
|
119 |
+
total_loss = 0
|
120 |
+
logs = {}
|
121 |
+
for loss_name, weight, loss in self.losses:
|
122 |
+
ls_mask = loss(logits, masks)
|
123 |
+
total_loss += weight * ls_mask
|
124 |
+
logs[f"train_mask_{loss_name}"] = ls_mask
|
125 |
+
|
126 |
+
logs["train_loss"] = total_loss
|
127 |
+
|
128 |
+
logs["lr"] = self._get_current_lr()
|
129 |
+
|
130 |
+
return {"loss": total_loss, "log": logs}
|
131 |
+
|
132 |
+
def _get_current_lr(self) -> torch.Tensor:
|
133 |
+
lr = [x["lr"] for x in self.optimizers[0].param_groups][0] # type: ignore
|
134 |
+
return torch.Tensor([lr])[0].cuda()
|
135 |
+
|
136 |
+
def validation_step(self, batch, batch_id):
|
137 |
+
features = batch["features"]
|
138 |
+
masks = batch["masks"]
|
139 |
+
|
140 |
+
logits = self.forward(features)
|
141 |
+
|
142 |
+
result = {}
|
143 |
+
for loss_name, _, loss in self.losses:
|
144 |
+
result[f"val_mask_{loss_name}"] = loss(logits, masks)
|
145 |
+
|
146 |
+
result["val_iou"] = binary_mean_iou(logits, masks)
|
147 |
+
|
148 |
+
return result
|
149 |
+
|
150 |
+
def validation_epoch_end(self, outputs):
|
151 |
+
logs = {"epoch": self.trainer.current_epoch}
|
152 |
+
|
153 |
+
avg_val_iou = find_average(outputs, "val_iou")
|
154 |
+
|
155 |
+
logs["val_iou"] = avg_val_iou
|
156 |
+
|
157 |
+
return {"val_iou": avg_val_iou, "log": logs}
|
158 |
+
|
159 |
+
|
160 |
+
def main():
|
161 |
+
args = get_args()
|
162 |
+
|
163 |
+
with open(args.config_path) as f:
|
164 |
+
hparams = yaml.load(f, Loader=yaml.SafeLoader)
|
165 |
+
|
166 |
+
pipeline = SegmentPeople(hparams)
|
167 |
+
|
168 |
+
Path(hparams["checkpoint_callback"]["filepath"]).mkdir(exist_ok=True, parents=True)
|
169 |
+
|
170 |
+
trainer = object_from_dict(
|
171 |
+
hparams["trainer"],
|
172 |
+
logger=WandbLogger(hparams["experiment_name"]),
|
173 |
+
checkpoint_callback=object_from_dict(hparams["checkpoint_callback"]),
|
174 |
+
)
|
175 |
+
|
176 |
+
trainer.fit(pipeline)
|
177 |
+
|
178 |
+
|
179 |
+
if __name__ == "__main__":
|
180 |
+
main()
|
cloths_segmentation/utils.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
from typing import Union, Dict, List, Tuple
|
3 |
+
|
4 |
+
|
5 |
+
def get_id2_file_paths(path: Union[str, Path]) -> Dict[str, Path]:
|
6 |
+
return {x.stem: x for x in Path(path).glob("*.*")}
|
7 |
+
|
8 |
+
|
9 |
+
def get_samples(image_path: Path, mask_path: Path) -> List[Tuple[Path, Path]]:
|
10 |
+
"""Couple masks and images.
|
11 |
+
|
12 |
+
Args:
|
13 |
+
image_path:
|
14 |
+
mask_path:
|
15 |
+
|
16 |
+
Returns:
|
17 |
+
"""
|
18 |
+
|
19 |
+
image2path = get_id2_file_paths(image_path)
|
20 |
+
mask2path = get_id2_file_paths(mask_path)
|
21 |
+
|
22 |
+
return [(image_file_path, mask2path[file_id]) for file_id, image_file_path in image2path.items()]
|
rb.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import torch
|
4 |
+
import albumentations as albu
|
5 |
+
from iglovikov_helper_functions.utils.image_utils import load_rgb, pad, unpad
|
6 |
+
from iglovikov_helper_functions.dl.pytorch.utils import tensor_from_rgb_image
|
7 |
+
|
8 |
+
from cloths_segmentation.pre_trained_models import create_model
|
9 |
+
model = create_model("Unet_2020-10-30")
|
10 |
+
model.eval()
|
11 |
+
|
12 |
+
image = cv2.imread(str(r"test.jpg"))
|
13 |
+
image_2_extract = image
|
14 |
+
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
15 |
+
transform = albu.Compose([albu.Normalize(p=1)], p=1)
|
16 |
+
padded_image, pads = pad(image, factor=32, border=cv2.BORDER_CONSTANT)
|
17 |
+
x = transform(image=padded_image)["image"]
|
18 |
+
x = torch.unsqueeze(tensor_from_rgb_image(x), 0)
|
19 |
+
|
20 |
+
with torch.no_grad():
|
21 |
+
prediction = model(x)[0][0]
|
22 |
+
mask = (prediction > 0).cpu().numpy().astype(np.uint8)
|
23 |
+
mask = unpad(mask, pads)
|
24 |
+
rmask = (cv2.cvtColor(mask, cv2.COLOR_BGR2RGB) * 255).astype(np.uint8)
|
25 |
+
mask2 = np.where((rmask < 255), 0, 1).astype('uint8')
|
26 |
+
image_2_extract = image_2_extract * mask2[:, :, 1, np.newaxis]
|
27 |
+
|
28 |
+
tmp = cv2.cvtColor(image_2_extract, cv2.COLOR_BGR2GRAY)
|
29 |
+
_, alpha = cv2.threshold(tmp, 0, 255, cv2.THRESH_BINARY)
|
30 |
+
b, g, r = cv2.split(image_2_extract)
|
31 |
+
rgba = [b, g, r, alpha]
|
32 |
+
dst = cv2.merge(rgba, 4)
|
33 |
+
cv2.imwrite("test.png", dst)
|
34 |
+
# cv2.waitKey(0)
|
semgent_from_folder.py
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# import os
|
2 |
+
# import cv2
|
3 |
+
# import numpy as np
|
4 |
+
# import torch
|
5 |
+
# import albumentations as albu
|
6 |
+
# from iglovikov_helper_functions.utils.image_utils import load_rgb, pad, unpad
|
7 |
+
# from iglovikov_helper_functions.dl.pytorch.utils import tensor_from_rgb_image
|
8 |
+
# from cloths_segmentation.pre_trained_models import create_model
|
9 |
+
# from tqdm import tqdm
|
10 |
+
|
11 |
+
|
12 |
+
# model = create_model("Unet_2020-10-30")
|
13 |
+
# model.to("cuda")
|
14 |
+
# model.eval()
|
15 |
+
|
16 |
+
# input_dir = "../../image"
|
17 |
+
# output_dir = "../../seg_masks"
|
18 |
+
|
19 |
+
# os.makedirs(output_dir, exist_ok=True)
|
20 |
+
|
21 |
+
# for image_filename in tqdm(os.listdir(input_dir), colour="green"):
|
22 |
+
# image_path = os.path.join(input_dir, image_filename)
|
23 |
+
|
24 |
+
# image = cv2.imread(image_path)
|
25 |
+
# image_2_extract = image
|
26 |
+
# image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
27 |
+
# transform = albu.Compose([albu.Normalize(p=1)], p=1)
|
28 |
+
# padded_image, pads = pad(image, factor=32, border=cv2.BORDER_CONSTANT)
|
29 |
+
# x = transform(image=padded_image)["image"]
|
30 |
+
# x = torch.unsqueeze(tensor_from_rgb_image(x), 0).to("cuda")
|
31 |
+
|
32 |
+
# with torch.no_grad():
|
33 |
+
# prediction = model(x)[0][0]
|
34 |
+
# mask = (prediction > 0).cpu().numpy().astype(np.uint8)
|
35 |
+
# mask = unpad(mask, pads)
|
36 |
+
# rmask = (cv2.cvtColor(mask, cv2.COLOR_BGR2RGB) * 255).astype(np.uint8)
|
37 |
+
# mask2 = np.where((rmask < 255), 0, 1).astype('uint8')
|
38 |
+
# image_2_extract = image_2_extract * mask2[:, :, 1, np.newaxis]
|
39 |
+
|
40 |
+
# tmp = cv2.cvtColor(image_2_extract, cv2.COLOR_BGR2GRAY)
|
41 |
+
# _, alpha = cv2.threshold(tmp, 0, 255, cv2.THRESH_BINARY)
|
42 |
+
# b, g, r = cv2.split(image_2_extract)
|
43 |
+
# rgba = [b, g, r, alpha]
|
44 |
+
# dst = cv2.merge(rgba, 4)
|
45 |
+
|
46 |
+
# output_image_path = os.path.join(output_dir, image_filename.replace(".jpg", ".png"))
|
47 |
+
# cv2.imwrite(output_image_path, dst)
|
48 |
+
|
49 |
+
# # break
|
50 |
+
|
51 |
+
|
52 |
+
|
53 |
+
import os
|
54 |
+
import cv2
|
55 |
+
import numpy as np
|
56 |
+
import torch
|
57 |
+
import albumentations as albu
|
58 |
+
from iglovikov_helper_functions.utils.image_utils import load_rgb, pad, unpad
|
59 |
+
from iglovikov_helper_functions.dl.pytorch.utils import tensor_from_rgb_image
|
60 |
+
from cloths_segmentation.pre_trained_models import create_model
|
61 |
+
from tqdm import tqdm
|
62 |
+
|
63 |
+
# Create the model and wrap it with DataParallel
|
64 |
+
model = create_model("Unet_2020-10-30")
|
65 |
+
model = torch.nn.DataParallel(model)
|
66 |
+
|
67 |
+
# Move the model to CUDA devices
|
68 |
+
model.to("cuda")
|
69 |
+
model.eval()
|
70 |
+
|
71 |
+
input_dir = "../../image"
|
72 |
+
output_dir = "../../seg_masks"
|
73 |
+
|
74 |
+
os.makedirs(output_dir, exist_ok=True)
|
75 |
+
|
76 |
+
for image_filename in tqdm(os.listdir(input_dir), colour="green"):
|
77 |
+
image_path = os.path.join(input_dir, image_filename)
|
78 |
+
|
79 |
+
image = cv2.imread(image_path)
|
80 |
+
image_2_extract = image
|
81 |
+
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
82 |
+
transform = albu.Compose([albu.Normalize(p=1)], p=1)
|
83 |
+
padded_image, pads = pad(image, factor=32, border=cv2.BORDER_CONSTANT)
|
84 |
+
x = transform(image=padded_image)["image"]
|
85 |
+
x = torch.unsqueeze(tensor_from_rgb_image(x), 0).to("cuda")
|
86 |
+
|
87 |
+
with torch.no_grad():
|
88 |
+
# Use DataParallel to perform inference on all 4 GPUs
|
89 |
+
prediction = model(x)[0][0]
|
90 |
+
mask = (prediction > 0).cpu().numpy().astype(np.uint8)
|
91 |
+
mask = unpad(mask, pads)
|
92 |
+
rmask = (cv2.cvtColor(mask, cv2.COLOR_BGR2RGB) * 255).astype(np.uint8)
|
93 |
+
mask2 = np.where((rmask < 255), 0, 1).astype('uint8')
|
94 |
+
image_2_extract = image_2_extract * mask2[:, :, 1, np.newaxis]
|
95 |
+
|
96 |
+
tmp = cv2.cvtColor(image_2_extract, cv2.COLOR_BGR2GRAY)
|
97 |
+
_, alpha = cv2.threshold(tmp, 0, 255, cv2.THRESH_BINARY)
|
98 |
+
b, g, r = cv2.split(image_2_extract)
|
99 |
+
rgba = [b, g, r, alpha]
|
100 |
+
dst = cv2.merge(rgba, 4)
|
101 |
+
|
102 |
+
output_image_path = os.path.join(output_dir, image_filename.replace(".jpg", ".png"))
|
103 |
+
cv2.imwrite(output_image_path, dst)
|
104 |
+
|
105 |
+
# break
|
test.jpg
ADDED
![]() |
test.png
ADDED
![]() |
Git LFS Details
|