-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.py
281 lines (268 loc) · 11.6 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
import click
from dataloader import CLASS_LABELS, ORIGINAL_IMAGE
from omegaconf import OmegaConf
def set_env(gpus: str = '-1'):
import os
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]=gpus
os.environ["TF_GPU_THREAD_MODE"]="gpu_private"
os.environ["TF_FORCE_GPU_ALLOW_GROWTH"]='true'
import tensorflow as tf
print(f'CUDA AVAILABLE: {tf.test.is_gpu_available(cuda_only=True)}')
print(f'TENSORFLOW VERSION: {tf.__version__}')
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
try:
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
logical_devices = tf.config.experimental.list_logical_devices('GPU')
print(f'PHYSICAL GPUs: {len(gpus)}')
print(f'LOGICAL GPUs: {len(logical_devices)}')
except RuntimeError as e:
print(f'ERROR: {e}') # Memory growth must be set before GPUs have been initialized
else:
print('WARNING: no GPU found!')
@click.group()
@click.pass_context
def main(ctx):
"""
Training and evaluation
"""
print("Mode:", ctx.invoked_subcommand)
@main.command()
@click.option(
"-c",
"--config-path",
type=click.File(),
required=True,
help="Dataset configuration file in YAML",
)
@click.option(
"--cuda",
is_flag=True,
help="Enable CUDA if available"
)
def train(config_path: str, cuda: bool = True):
"""
Training ViT-PCM
"""
CONFIG = OmegaConf.load(config_path)
GPUs = CONFIG.EXP.NUM_GPUS if cuda else '-1'
set_env(gpus=GPUs)
import os
import tensorflow as tf
tf.random.set_seed(1234)
from utils import create_folders
from tensorflow.keras.optimizers import Adam
from dataloader import DatasetVITPCMDistributed
from tensorflow.summary import create_file_writer
from tensorflow.keras.callbacks import TensorBoard, ModelCheckpoint, EarlyStopping
from model import get_model, ConfusionMatrixCallback
GPUS = ["GPU:"+str(i) for i in range(len(GPUs.split(',')))]
strategy = tf.distribute.MirroredStrategy(devices=GPUS,
cross_device_ops=tf.distribute.HierarchicalCopyAllReduce())
REPLICAS = strategy.num_replicas_in_sync
logdir, filepath = create_folders(CONFIG)
writer = create_file_writer(logdir)
writer.set_as_default()
callbacks = TensorBoard(log_dir=logdir, histogram_freq=15, write_graph=False,
write_images=False, update_freq='batch', profile_batch=(10),
embeddings_freq=15, embeddings_metadata=None)
checkpoint = ModelCheckpoint(filepath=filepath, save_weights_only=True,
monitor='val_mean_iou', mode='max',
save_best_only=True, verbose=1)
confmatrix = ConfusionMatrixCallback(basedir=logdir)
earlystop = EarlyStopping(monitor='val_mean_iou',patience=60,
verbose=1,mode='max',restore_best_weights=True)
with strategy.scope():
model = get_model(CONFIG)
model.warmup()
model.compile(Adam(learning_rate=CONFIG.SOLVER.LR_WARMUP, name='adam'))
train_set = DatasetVITPCMDistributed(CONFIG, 'train', REPLICAS).get_dataset()
val_set = DatasetVITPCMDistributed(CONFIG, 'val', REPLICAS).get_dataset()
_ = model.fit(train_set, epochs=CONFIG.SOLVER.EPOCHS_WARMUP,
validation_data=val_set,validation_freq=1, max_queue_size=1e10,
callbacks=[callbacks, checkpoint, confmatrix, earlystop],
use_multiprocessing=False, workers=CONFIG.DATALOADER.NUM_WORKERS)
with strategy.scope():
model.unfreeze()
model.compile(Adam(learning_rate=CONFIG.SOLVER.LR, name='adam'))
# train_set = DatasetVITPCMDistributed(config_path, 'train', REPLICAS)
_ = model.fit(train_set, initial_epoch=CONFIG.SOLVER.EPOCHS_WARMUP, epochs=CONFIG.SOLVER.EPOCHS,
validation_data=val_set,validation_freq=1, max_queue_size=1e10,
callbacks=[callbacks, checkpoint, confmatrix, earlystop],
use_multiprocessing=False, workers=CONFIG.DATALOADER.NUM_WORKERS)
model.evaluate(val_set, batch_size=CONFIG.SOLVER.BATCH_SIZE.VAL*REPLICAS, callbacks=[callbacks])
@main.command()
@click.option(
"-c",
"--config-path",
type=click.File(),
required=True,
help="Dataset configuration file in YAML",
)
@click.option(
"-m",
"--model-path",
type=click.STRING,
required=True,
help="Model weights path",
)
@click.option(
"--cuda",
is_flag=True,
help="Enable CUDA if available"
)
def eval(config_path, model_path, cuda):
"""
Fast distributed evaluation of ViT-PCM
"""
CONFIG = OmegaConf.load(config_path)
GPUs = CONFIG.EXP.NUM_GPUS if cuda else '-1'
set_env(gpus=GPUs)
import tensorflow as tf
tf.random.set_seed(1234)
from model import get_model
from tensorflow.keras.optimizers import Adam
from dataloader import DatasetVITPCMDistributed
GPUS = ["GPU:"+str(i) for i in range(len(GPUs.split(',')))]
strategy = tf.distribute.MirroredStrategy(devices=GPUS,
cross_device_ops=tf.distribute.HierarchicalCopyAllReduce())
REPLICAS = strategy.num_replicas_in_sync
CONFIG.MODEL.INIT_MODEL = model_path
with strategy.scope():
model = get_model(CONFIG)
model.compile(Adam(learning_rate=CONFIG.SOLVER.LR_WARMUP, name='adam'))
model.trainable = False
model.show()
val_set = DatasetVITPCMDistributed(CONFIG, 'val', REPLICAS).get_dataset()
results = model.evaluate(val_set, batch_size=CONFIG.SOLVER.BATCH_SIZE.VAL*REPLICAS, use_multiprocessing=True, workers=CONFIG.DATALOADER.NUM_WORKERS, return_dict=True)
print(f'[INFO]: Evaluation \n{results}')
print(f'[INFO]: mIoU \n{model.metrics[-1].summary()}')
@main.command()
@click.option(
"-c",
"--config-path",
type=click.File(),
required=True,
help="Dataset configuration file in YAML",
)
@click.option(
"-m",
"--model-path",
type=click.STRING,
required=True,
help="Model weights path",
)
@click.option(
"--crf",
is_flag=True,
help="Run CRF refinement after inference"
)
@click.option(
"--cuda",
is_flag=True,
help="Enable CUDA if available"
)
def test(config_path, model_path, crf, cuda):
"""
Infer and evaluate (if seg labels are present) ViT-PCM on any specified set
"""
CONFIG = OmegaConf.load(config_path)
from os import makedirs
from os.path import join, isfile
out_dir = CONFIG.EXP.OUTPUT_DIR
makedirs(out_dir,exist_ok=True)
out_dir = join(out_dir,CONFIG.EXP.ID)
makedirs(out_dir,exist_ok=True)
out_dir = join(out_dir,CONFIG.EXP.RESULTS_DIR)
makedirs(out_dir,exist_ok=True)
out_dir = join(out_dir,CONFIG.DATASET.SPLIT.TEST)
for p in [out_dir,join(out_dir,'preds'),join(out_dir,'segs')]: makedirs(p,exist_ok=True)
GPUs = CONFIG.EXP.NUM_GPUS if cuda else '-1'
set_env(gpus=GPUs)
import tensorflow as tf
tf.random.set_seed(1234)
from model import get_model, MeanIoUWrapper
CONFIG.MODEL.INIT_MODEL = model_path
model = get_model(CONFIG)
model.trainable = False
model.show()
from dataloader import DatasetVITPCMDistributed, IMAGE, HEIGHT, WIDTH, IMAGE_NAME, CLASS_LABELS, ORIGINAL_LABEL
data_set = DatasetVITPCMDistributed(CONFIG, 'test', 1).get_dataset()
from utils import resize, create_pascal_label_colormap, preds2dict, dict2preds, ignore_labels, tensor
import numpy as np
from PIL import Image
import json
from tqdm import tqdm
palette = create_pascal_label_colormap()
miou = MeanIoUWrapper(CONFIG.DATASET.NUM_CLASSES)
print('[INFO]: Running inference..')
print(f'[INFO]: Output directory {out_dir}')
for data in (bar := tqdm(iterable=iter(data_set),total=len(data_set))):
image_name = str(data.get(IMAGE_NAME).numpy()[0].decode('UTF-8'))
preds = model.infer(data.get(IMAGE), data.get(CLASS_LABELS) if CLASS_LABELS in data else None) # class labels is None on test set
np.save(join(out_dir,'preds',image_name+'.npy'), preds2dict(preds.numpy()[0],data.get(CLASS_LABELS).numpy()[0] if CLASS_LABELS in data else None), allow_pickle=True)
seg_preds = tf.argmax(resize(preds, (data.get(HEIGHT)[0], data.get(WIDTH)[0])), axis=-1)
pil_seg = Image.fromarray(seg_preds.numpy().astype(np.uint8)[0])
pil_seg.putpalette(palette)
pil_seg.save(join(out_dir,'segs',image_name+'.png'))
if ORIGINAL_LABEL in data:
miou.update_state(ignore_labels(data.get(ORIGINAL_LABEL), ignore_value=CONFIG.DATASET.IGNORE_LABEL),\
ignore_labels(seg_preds, data.get(ORIGINAL_LABEL), ignore_value=CONFIG.DATASET.IGNORE_LABEL))
bar.set_description(f'[INFO]: mIoU {round(float(miou.result().numpy()),4)}')
if np.any(miou.total_cm.numpy()):
np.save(join(out_dir,'miou_matrix.npy'),miou.total_cm.numpy())
with open(join(out_dir,'miou_summary.txt'), "w") as f:
json.dump(miou.summary(), f, indent=4, sort_keys=True)
if crf:
import joblib
import warnings
# suppress joblib warning (to be understood)
warnings.filterwarnings("ignore")
print('[INFO]: Running CRF post-processing..')
from crf import DenseCRF
makedirs(join(out_dir,'crf'),exist_ok=True)
# CRF post-processor
postprocessor = DenseCRF(
iter_max=CONFIG.CRF.ITER_MAX,
pos_xy_std=CONFIG.CRF.POS_XY_STD,
pos_w=CONFIG.CRF.POS_W,
bi_xy_std=CONFIG.CRF.BI_XY_STD,
bi_rgb_std=CONFIG.CRF.BI_RGB_STD,
bi_w=CONFIG.CRF.BI_W,
)
iterator = data_set.as_numpy_iterator()
# Process per sample
def process(data):
label = data.get(ORIGINAL_LABEL)[0] if ORIGINAL_LABEL in data else None
image = data.get(ORIGINAL_IMAGE)[0].astype(np.uint8)
image_name = str(data.get(IMAGE_NAME)[0].decode('UTF-8'))
npy_path = join(out_dir,'preds',image_name+'.npy')
if not isfile(npy_path): raise ValueError('[ERROR]: file doesn\'t exist')
preds = dict2preds(np.load(npy_path, allow_pickle=True).item(), CONFIG.DATASET.NUM_CLASSES)
preds = resize(preds,(data.get(HEIGHT)[0], data.get(WIDTH)[0]))
crf_preds = np.transpose(postprocessor(image, np.transpose(preds,(2,0,1))),(1,2,0)) # h w c -> c h w
crf_segs = np.argmax(crf_preds, axis=-1).astype(np.uint8)
pil_seg = Image.fromarray(crf_segs)
pil_seg.putpalette(palette)
pil_seg.save(join(out_dir,'crf',image_name+'.png'))
return crf_segs, label, image_name
# CRF in multi-process
results = joblib.Parallel(n_jobs=CONFIG.DATALOADER.NUM_WORKERS, verbose=10, pre_dispatch="all")(
[joblib.delayed(process)(next(iterator)) for i in range(len(data_set))]
)
seg_preds, labels, image_names = zip(*results)
if not all(isinstance(l,type(None)) for l in labels):
# Pixel Accuracy, Mean Accuracy, Class IoU, Mean IoU, Freq Weighted IoU
miou = MeanIoUWrapper(CONFIG.DATASET.NUM_CLASSES)
print('[INFO]: Compute stats after post-processing..')
for l, p in zip(labels, seg_preds):
miou.update_state(ignore_labels(tensor(l), ignore_value=CONFIG.DATASET.IGNORE_LABEL),\
ignore_labels(tensor(p), tensor(l), ignore_value=CONFIG.DATASET.IGNORE_LABEL))
np.save(join(out_dir,'miou_matrix_crf.npy'),miou.total_cm.numpy())
with open(join(out_dir,f'miou_summary_crf.txt'), "w") as f:
json.dump(miou.summary(), f, indent=4, sort_keys=True)
print(f'[INFO]: mIoU {round(float(miou.result().numpy()),4)}')
if __name__ == "__main__":
main()