diff --git a/bin/blend_mask_s21.py b/bin/blend_mask_s21.py deleted file mode 100755 index b331e25e..00000000 --- a/bin/blend_mask_s21.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 - -import os - -import cv2 -import numpy as np -import tqdm - -from saicinpainting.evaluation.data import PrecomputedInpaintingResultsDataset -from saicinpainting.evaluation.utils import load_yaml - - -def main(args): - config = load_yaml(args.config) - - if not args.predictdir.endswith('/'): - args.predictdir += '/' - - dataset = PrecomputedInpaintingResultsDataset(args.datadir, args.predictdir, **config.dataset_kwargs) - - os.makedirs(os.path.dirname(args.outpath), exist_ok=True) - - for img_i in tqdm.trange(len(dataset)): - try: - pred_fname = dataset.pred_filenames[img_i] - cur_out_fname = os.path.join(args.outpath, pred_fname[len(args.predictdir):]) - os.makedirs(os.path.dirname(cur_out_fname), exist_ok=True) - - sample = dataset[img_i] - img = sample['image'] - mask = sample['mask'] - inpainted = sample['inpainted'] - - cur_res = (1 - mask) * img + mask * inpainted - - cur_res = np.clip(np.transpose(cur_res, (1, 2, 0)) * 255, 0, 255).astype('uint8') - cur_res = cv2.cvtColor(cur_res, cv2.COLOR_RGB2BGR) - cv2.imwrite(cur_out_fname, cur_res) - except Exception as ex: - print(f'Failed to process {img_i}, {pred_fname} due to {ex}') - - -if __name__ == '__main__': - import argparse - - aparser = argparse.ArgumentParser() - aparser.add_argument('config', type=str, help='Path to evaluation config') - aparser.add_argument('datadir', type=str, - help='Path to folder with images and masks (output of gen_mask_dataset.py)') - aparser.add_argument('predictdir', type=str, - help='Path to folder with predicts (e.g. predict_hifill_baseline.py)') - aparser.add_argument('outpath', type=str, help='Where to put results') - - main(aparser.parse_args()) diff --git a/bin/gen_val_samples_s21.py b/bin/gen_val_samples_s21.py deleted file mode 100755 index 9ba16181..00000000 --- a/bin/gen_val_samples_s21.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 - -import logging -import os -import sys -import traceback - -from saicinpainting.evaluation.utils import move_to_device - -os.environ['OMP_NUM_THREADS'] = '1' -os.environ['OPENBLAS_NUM_THREADS'] = '1' -os.environ['MKL_NUM_THREADS'] = '1' -os.environ['VECLIB_MAXIMUM_THREADS'] = '1' -os.environ['NUMEXPR_NUM_THREADS'] = '1' - -import cv2 -import hydra -import numpy as np -import torch -import tqdm -import yaml -from omegaconf import OmegaConf -from torch.utils.data._utils.collate import default_collate - -from saicinpainting.training.data.datasets import make_default_val_dataset -from saicinpainting.training.trainers import load_checkpoint -from saicinpainting.utils import register_debug_signal_handlers - -LOGGER = logging.getLogger(__name__) - - -@hydra.main(config_path='../configs/prediction', config_name='default.yaml') -def main(predict_config: OmegaConf): - try: - register_debug_signal_handlers() # kill -10 will result in traceback dumped into log - - if not predict_config.indir.endswith('/'): - predict_config.indir += '/' - - dataset = make_default_val_dataset(predict_config.indir, **predict_config.dataset) - - with torch.no_grad(): - for img_i in tqdm.trange(len(dataset)): - mask_fname = dataset.mask_filenames[img_i] - cur_out_fname = os.path.join(predict_config.outdir, os.path.splitext(mask_fname[len(predict_config.indir):])[0] + '.png') - os.makedirs(os.path.dirname(cur_out_fname), exist_ok=True) - - sample = dataset[img_i] - img = sample['image'] - mask = sample['mask'] - - cur_res = (1 - mask) * img + mask * np.array([0, 1.0, 0])[..., None, None] - - cur_res = np.clip(np.transpose(cur_res, (1, 2, 0)) * 255, 0, 255).astype('uint8') - cur_res = cv2.cvtColor(cur_res, cv2.COLOR_RGB2BGR) - cv2.imwrite(cur_out_fname, cur_res) - except KeyboardInterrupt: - LOGGER.warning('Interrupted by user') - except Exception as ex: - LOGGER.critical(f'Prediction failed due to {ex}:\n{traceback.format_exc()}') - sys.exit(1) - - -if __name__ == '__main__': - main() diff --git a/bin/parse_logs_and_download.py b/bin/parse_logs_and_download.py deleted file mode 100644 index dee17b70..00000000 --- a/bin/parse_logs_and_download.py +++ /dev/null @@ -1,164 +0,0 @@ -import os -import re -import pathlib - -import yaml -import pandas as pd -from tqdm import tqdm - -ROOT_PATH = "/mnt/storage/images" -CLUSTER_EXP_PATH = "/vol1/dbstore/orc_srr/multimodal/a.mashikhin/inpainting/experiments/" -folders = [ - # list of folders -] - - -def save_txt_metrics(folder, metrics_block, params): - metrics_str = "Validation metrics after epoch #"+metrics_block[:-1] + f"\n\n Params: {round(params,1)}M" - path = os.path.join(ROOT_PATH, folder, f"best_metrics.txt") - text_file = open(path, "w") - text_file.write(metrics_str) - text_file.close() - - -def convert_log_to_metrics(file): - df = [] - for i, metrics_block in enumerate(file.split("saicinpainting.training.trainers.base][INFO] - Validation metrics after epoch #")): - if i == 0: - continue - ts = re.findall('\[(.*?)\]', metrics_block)[0] - - metrics_block_raw = metrics_block.split(ts)[0] - epoch = metrics_block_raw.split(", total")[0] - metrics_list = metrics_block_raw.split("\n")[-2].split() - d = {"epoch": int(epoch), - "fid_mean": float(metrics_list[1]), - "fid_std": float(metrics_list[2]), - "lpips_mean": float(metrics_list[3]), - "lpips_std": float(metrics_list[4]), - "ssim_mean": float(metrics_list[5]), - "ssim_std": float(metrics_list[6]), - "ssim_fid100_f1_mean": float(metrics_list[7]), - "ssim_fid100_f1_std": float(metrics_list[8]), - } - df.append(d) - df = pd.DataFrame(df).drop_duplicates("epoch") - df = df.sort_values("ssim_fid100_f1_mean", ascending=False) - return df, metrics_block_raw - - -def download_latest_logs(folder): - output_path = os.path.join(ROOT_PATH, folder) - pathlib.Path(output_path).mkdir(exist_ok=True, parents=True) - exp_folder = os.path.join(CLUSTER_EXP_PATH, folder) - os.system(f"rsync -av --delete korea:{exp_folder}/train.log {output_path}") - if not os.path.exists(os.path.join(output_path, "config.yaml")): - os.system(f"rsync -av korea:{exp_folder}/config.yaml {output_path}") - - -def download_best_images(folder, epoch): - print(f"Downloading sample for {folder}, epoch = {epoch}") - output_path = os.path.join(ROOT_PATH, folder, "samples") - pathlib.Path(output_path).mkdir(exist_ok=True, parents=True) - exp_folder = os.path.join(CLUSTER_EXP_PATH, folder, "samples", f"epoch{epoch:04d}_test") - os.system(f"rsync -av korea:{exp_folder} {output_path}") - - -def main(): - result = {} - for folder in tqdm(folders): - exp_name = folder - download_latest_logs(folder) - path = os.path.join(ROOT_PATH, folder, "train.log") - with open(path) as f: - file = f.read() - - # metrics - metrics_df, metrics_block = convert_log_to_metrics(file) - best_metrics = metrics_df.iloc[0].to_dict() - d = best_metrics - - # model - params = file.split("generator | ")[1].split("discriminator")[0].strip().replace("|", "").split()[1].strip() - yaml_config_path = os.path.join(ROOT_PATH, folder, 'config.yaml') - with open(yaml_config_path, 'r') as stream: - config = yaml.safe_load(stream) - params = float(params) - d.update({"ngf": config['generator']['ngf'], - "n_blocks": config['generator']['n_blocks'], - "kind": config['generator']['kind'], - "dilation_num" : config['generator'].get("multidilation_kwargs", {}).get("dilation_num", 0), - "params": params}) - result[exp_name] = d - save_txt_metrics(folder, metrics_block, params) - download_best_images(folder, int(best_metrics['epoch'])) - - -def plot() - import matplotlib.pyplot as plt - import matplotlib - import matplotlib.patches as mpatches - %matplotlib inline - plt.style.use(['default']) - matplotlib.rcParams.update({'font.size': 22}) - - x = [] - y = [] - plot_df = [] - for k,v in result.items(): - new_v = {"name": k} - new_v.update(v) - plot_df.append(new_v) - plot_df = pd.DataFrame(plot_df) - - - def get_label_and_color(kind, n_block, ngf, dilation_num): - if kind == "pix2pixhd_global": - k="" - color = "green" - elif kind == "pix2pixhd_multidilated": - k="_dil" - if dilation_num == 2: - post = "2" - color = "red" - elif dilation_num == 4: - post = "4" - color = "purple" - else: - raise NotImplementedError( f"dilation_num= {dilation_num}") - k = f"{k}{post}" - else: - raise NotImplementedError(kind) - label = f"b{n_block}_n{ngf}{k}" - return label, color - - tmp_df = plot_df[plot_df['epoch'] > 0].sort_values("params") - x = tmp_df['params'].tolist() - y = tmp_df['ssim_fid100_f1_mean'].tolist() - kind = tmp_df['kind'].tolist() - n_block = tmp_df['n_blocks'].tolist() - ngf = tmp_df['ngf'].tolist() - dilation_num = tmp_df['dilation_num'].tolist() - name = tmp_df['name'].tolist() - - f,ax = plt.subplots(1,1,figsize=(20,12)) - - ax.scatter(x,y, color="black") - for i in range(len(tmp_df)): - label, color = get_label_and_color(kind=kind[i], n_block=n_block[i], ngf=ngf[i], dilation_num=dilation_num[i]) - p = round(y[i]/0.9043 *100,1) - ax.annotate(f"{label}({p}%)", (x[i], y[i]), fontsize=18, color=color) - - ax.set_xlabel("params (M)") - ax.set_ylabel("ssim_fid100_f1") - ax.set_title("Distillation of SOTA (ssim_fid100_f1 =0.9043)") - patches = [mpatches.Patch(color='green', label='Normal convs'), - mpatches.Patch(color='red', label='Dilated convs CATin (dil_num=2)'), - mpatches.Patch(color='purple', label='Dilated convs CATin (dil_num=4). (all <= 6 epochs)'),] - ax.legend(handles=patches, loc=4) - ax.grid() - plt.savefig("1.png", format='png', bbox_inches='tight') - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/bin/process_debug.sh b/bin/process_debug.sh deleted file mode 100755 index 31edbeec..00000000 --- a/bin/process_debug.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -DIRNAME="$(dirname $0)" - -$DIRNAME/gen_mask_dataset.py $DIRNAME/../configs/gen_dataset1.yaml \ - /data/inpainting/Places365/debug \ - /data/inpainting/Places365/debug_masks1 \ - --n-jobs 6 - -$DIRNAME/calc_dataset_stats.py /data/inpainting/Places365/debug_masks1 \ - /data/inpainting/Places365/debug_masks1_summary \ - --samples-n 20 - -$DIRNAME/predict_hifill_baseline.py /data/inpainting/Places365/debug_masks1 \ - /data/inpainting/Places365/debug_masks1_hifill - -$DIRNAME/evaluate_predicts.py $DIRNAME/../configs/eval1.yaml \ - /data/inpainting/Places365/debug_masks1 \ - /data/inpainting/Places365/debug_masks1_hifill \ - /data/inpainting/Places365/metrics/debug_masks1_hifill.csv diff --git a/bin/process_test_large.sh b/bin/process_test_large.sh deleted file mode 100755 index f7f3f84f..00000000 --- a/bin/process_test_large.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -DIRNAME="$(dirname $0)" - -$DIRNAME/gen_mask_dataset.py $DIRNAME/../configs/gen_dataset1.yaml \ - /data/inpainting/Places365/test_large \ - /data/inpainting/Places365/test_large_masks1 \ - --n-jobs 6 - -$DIRNAME/calc_dataset_stats.py /data/inpainting/Places365/test_large_masks1 \ - /data/inpainting/Places365/test_large_masks1_summary - -$DIRNAME/predict_hifill_baseline.py /data/inpainting/Places365/test_large_masks1 \ - /data/inpainting/Places365/test_large_masks1_hifill - -$DIRNAME/evaluate_predicts.py $DIRNAME/../configs/eval1.yaml \ - /data/inpainting/Places365/test_large_masks1 \ - /data/inpainting/Places365/test_large_masks1_hifill \ - /data/inpainting/Places365/metrics/test_large_masks1_hifill.csv diff --git a/bin/process_val_large.sh b/bin/process_val_large.sh deleted file mode 100755 index 564e8fd8..00000000 --- a/bin/process_val_large.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -DIRNAME="$(dirname $0)" - -$DIRNAME/gen_mask_dataset.py $DIRNAME/../configs/gen_dataset1.yaml \ - /data/inpainting/Places365/val_large \ - /data/inpainting/Places365/val_large_masks1 \ - --n-jobs 4 - -$DIRNAME/calc_dataset_stats.py /data/inpainting/Places365/val_large_masks1 \ - /data/inpainting/Places365/val_large_masks1_summary \ - --samples-n 20 - -$DIRNAME/predict_hifill_baseline.py /data/inpainting/Places365/val_large_masks1 \ - /data/inpainting/Places365/val_large_masks1_hifill - -$DIRNAME/evaluate_predicts.py $DIRNAME/../configs/eval1.yaml \ - /data/inpainting/Places365/val_large_masks1 \ - /data/inpainting/Places365/val_large_masks1_hifill \ - /data/inpainting/Places365/metrics/val_large_masks1_hifill.csv diff --git a/bin/process_val_large_random.sh b/bin/process_val_large_random.sh deleted file mode 100755 index 91171b78..00000000 --- a/bin/process_val_large_random.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -DIRNAME="$(dirname $0)" -DATA_ROOT=/data/inpainting/Places365 - -for config in random_medium_256 random_medium_512 random_thick_256 random_thick_512 random_thin_256 random_thin_512 -do - MASKS_OUTPATH=$DATA_ROOT/val_large_random_masks/$config - - $DIRNAME/gen_mask_dataset.py $DIRNAME/../configs/data_gen/$config.yaml \ - $DATA_ROOT/val_large \ - $MASKS_OUTPATH \ - --n-jobs 4 - - $DIRNAME/calc_dataset_stats.py $MASKS_OUTPATH \ - ${MASKS_OUTPATH}_summary \ - --samples-n 20 -done - diff --git a/bin/sinlge_image_segmentation.py b/bin/sinlge_image_segmentation.py deleted file mode 100644 index dc4fa050..00000000 --- a/bin/sinlge_image_segmentation.py +++ /dev/null @@ -1,190 +0,0 @@ -import argparse -import os -import pickle -import time -import random - -import cv2 -import colorsys - -import faiss - -import numpy as np -import torch -import torch.nn as nn -import torch.nn.functional as F -import torchvision -import torchvision.transforms as transforms -import torchvision.datasets as datasets - -import clustering - - -IMAGENET_MEAN = torch.FloatTensor([0.485, 0.456, 0.406])[None, :, None, None] -IMAGENET_STD = torch.FloatTensor([0.229, 0.224, 0.225])[None, :, None, None] - - -class VGG19(nn.Module): - def __init__(self, net='pytorch', normalize_inputs=True): - super(VGG19, self).__init__() - - self.normalize_inputs = normalize_inputs - self.mean_ = IMAGENET_MEAN - self.std_ = IMAGENET_STD - - vgg = torchvision.models.vgg19(pretrained=True).features - - for weights in vgg.parameters(): - weights.requires_grad = False - - vgg_avg_pooling = [] - for module in vgg.modules(): - if module.__class__.__name__ == 'Sequential': - continue - elif module.__class__.__name__ == 'MaxPool2d': - vgg_avg_pooling.append(nn.AvgPool2d(kernel_size=1, stride=1, padding=0)) - else: - vgg_avg_pooling.append(module) - - self.vgg = nn.Sequential(*vgg_avg_pooling[:-2]) - - def do_normalize_inputs(self, x): - return (x - self.mean_.to(x.device)) / self.std_.to(x.device) - - def forward(self, input): - if self.normalize_inputs: - input = self.do_normalize_inputs(input) - output = self.vgg(input) - return output - - -def random_colors(N, bright=True): - """ - Generate random colors. - To get visually distinct colors, generate them in HSV space then - convert to RGB. - """ - brightness = 1.0 if bright else 0.7 - hsv = [(float(i) / N, 1, brightness) for i in range(N)] - colors = list(map(lambda c: colorsys.hsv_to_rgb(*c), hsv)) - random.shuffle(colors) - return colors - - -def denormalize_inputs(x): - return x * IMAGENET_STD.to(x.device) + IMAGENET_MEAN.to(x.device) - -def parse_args(): - parser = argparse.ArgumentParser(description='PyTorch Implementation of DeepCluster') - - parser.add_argument('--data', type=str, help='path to dataset') - parser.add_argument('--clustering', type=str, choices=['Kmeans', 'PIC'], default='Kmeans') - parser.add_argument('--num_cluster', '--k', type=int, default=15) - parser.add_argument('--sobel', action='store_true', help='Sobel filtering') - - parser.add_argument('--batch', default=10, type=int) - parser.add_argument('--workers', default=4, type=int) - - return parser.parse_args() - - -def main(args): - print('-------------- args --------------') - print(args) - - - print('-------------- MODEL --------------') - model = VGG19().cuda() - print(model) - - - print('------------- ImageNet -------------') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - tra = [transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize] - - end = time.time() - dataset = datasets.ImageFolder(args.data, transform=transforms.Compose(tra)) - print('Load dataset: {0:.2f} s'.format(time.time() - end)) - - dataloader = torch.utils.data.DataLoader(dataset, - batch_size=args.batch, - num_workers=args.workers, - pin_memory=True) - - - print('-------------- feature infer -----------') - - for i, (input_tensor, _) in enumerate(dataloader): - with torch.no_grad(): - input_var = input_tensor.cuda() - features = model.forward(input_var) - - print( 'inputs:', input_var.shape, torch.min(input_var), torch.max(input_var)) - print('features:', features.shape) - - break - - b,c,h,w = input_var.size() - images = 255 * denormalize_inputs(input_var).permute(2,0,3,1).contiguous() # H x B x W x C - images = images.view(h, -1, c).cpu().numpy().astype(np.uint8) - - b,c,h,w = features.size() - features = features.view(b, c, -1).transpose(1,2).contiguous() # B x H*W x C - - xv, yv = torch.meshgrid([torch.arange(0,h), torch.arange(0,w)]) # H x W , H x W - xv = xv.view(1, h, w, 1) - yv = yv.view(1, h, w, 1) - coords = torch.cat([xv,yv], dim=3).cuda() # 1 x H x W x 2 - coords = coords.expand(size=(b,h,w,2)).view(b,-1, 2).contiguous().float() # B x H*W x 2 - - coords = coords / (h*w) - - print(' images:', images.shape) - print('features:', features.shape) - print(' coords:', coords.shape) - - #features = torch.cat([features, coords], dim=-1) - - print(' concat:', features.shape) - - - print('-------------- Clustering -----------') - - segmentations = [] - for idx in range(b): - feature = features[idx].cpu().numpy().astype(np.float32) - #coord = coords[idx].cpu().numpy() - coord = None - - clusterizer = clustering.__dict__[args.clustering](args.num_cluster) - I, loss = clusterizer.cluster(data=feature, - coord_grid=coord, - verbose=True) - cluster_map = np.array(I).reshape(h,w) - - segmentation = np.zeros(shape=(h,w,3)) - lbl_colors = random_colors(args.num_cluster) - for j, color in enumerate(lbl_colors): - segmentation[cluster_map==j] = color - segmentation = (255*segmentation).astype(np.uint8) - - print('segmentation:', segmentation.shape) - segmentations.append(segmentation) - - segmentations = np.concatenate(segmentations, axis=1) # along Width - - print('segmentations:', segmentations.shape) - - - result = np.concatenate([images,segmentations], axis=0) - - cv2.imwrite(f'batch0_img.png', result) - - -if __name__ == '__main__': - args = parse_args() - main(args=args) diff --git a/bin/train_benchmark.py b/bin/train_benchmark.py deleted file mode 100755 index 37499832..00000000 --- a/bin/train_benchmark.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 - -import logging -import os -import sys -import traceback - -os.environ['OMP_NUM_THREADS'] = '1' -os.environ['OPENBLAS_NUM_THREADS'] = '1' -os.environ['MKL_NUM_THREADS'] = '1' -os.environ['VECLIB_MAXIMUM_THREADS'] = '1' -os.environ['NUMEXPR_NUM_THREADS'] = '1' - -import hydra -from omegaconf import OmegaConf -from pytorch_lightning import Trainer -from pytorch_lightning.callbacks import ModelCheckpoint -from pytorch_lightning.loggers import TensorBoardLogger -from pytorch_lightning.plugins import DDPPlugin - -from saicinpainting.training.trainers import make_training_model -from saicinpainting.utils import register_debug_signal_handlers, \ - handle_ddp_subprocess, handle_ddp_parent_process, \ - handle_deterministic_config - - -from torch.profiler import profile, record_function, ProfilerActivity - -LOGGER = logging.getLogger(__name__) - - -@handle_ddp_subprocess() -@hydra.main(config_path='../configs/training', config_name='tiny_test.yaml') -def main(config: OmegaConf): - try: - need_set_deterministic = handle_deterministic_config(config) - - register_debug_signal_handlers() # kill -10 will result in traceback dumped into log - - is_in_ddp_subprocess = handle_ddp_parent_process() - - config.visualizer.outdir = os.path.join(os.getcwd(), config.visualizer.outdir) - if not is_in_ddp_subprocess: - LOGGER.info(OmegaConf.to_yaml(config)) - OmegaConf.save(config, os.path.join(os.getcwd(), 'config.yaml')) - - checkpoints_dir = os.path.join(os.getcwd(), 'models') - os.makedirs(checkpoints_dir, exist_ok=True) - - # there is no need to suppress this logger in ddp, because it handles rank on its own - metrics_logger = TensorBoardLogger(config.location.tb_dir, name=os.path.basename(os.getcwd())) - metrics_logger.log_hyperparams(config) - - training_model = make_training_model(config) - trainer_kwargs = OmegaConf.to_container(config.trainer.kwargs, resolve=True) - if need_set_deterministic: - trainer_kwargs['deterministic'] = True - - trainer = Trainer( - # there is no need to suppress checkpointing in ddp, because it handles rank on its own - callbacks=ModelCheckpoint(dirpath=checkpoints_dir, **config.trainer.checkpoint_kwargs), - logger=metrics_logger, - default_root_dir=os.getcwd(), - **trainer_kwargs - ) - trainer.fit(training_model) - - except KeyboardInterrupt: - LOGGER.warning('Interrupted by user') - except Exception as ex: - LOGGER.critical(f'Training failed due to {ex}:\n{traceback.format_exc()}') - sys.exit(1) - - -if __name__ == '__main__': - main()