From 3357facd173e3c952cbb32e8c5cd99d1441a7ab8 Mon Sep 17 00:00:00 2001 From: Stefan Klut Date: Mon, 22 Jul 2024 16:57:19 +0200 Subject: [PATCH] augmentations timing --- .../baseline/baseline_all_augments.yaml | 140 ++++++++++++++++++ data/augmentations.py | 41 +++-- data/numpy_transforms.py | 23 ++- data/test.py | 80 ++++++++++ data/torch_transforms.py | 8 +- 5 files changed, 278 insertions(+), 14 deletions(-) create mode 100644 configs/segmentation/baseline/baseline_all_augments.yaml create mode 100644 data/test.py diff --git a/configs/segmentation/baseline/baseline_all_augments.yaml b/configs/segmentation/baseline/baseline_all_augments.yaml new file mode 100644 index 0000000..3b34a09 --- /dev/null +++ b/configs/segmentation/baseline/baseline_all_augments.yaml @@ -0,0 +1,140 @@ +_BASE_: ../segmentation_base.yaml + +OUTPUT_DIR: ./output/baseline + +NAME: general_model + +PREPROCESS: + OVERWRITE: False + DISABLE_CHECK: False + + RESIZE: + RESIZE_MODE: "scaling" + SCALING: 0.5 + MAX_SIZE: -1 + + BASELINE: + LINE_WIDTH: 10 + SQUARE_LINES: True + +INPUT: + FORMAT: RGB + + RESIZE_MODE: "scaling" + SCALING_TRAIN: 1.0 + MAX_SIZE_TRAIN: -1 + + MAX_SIZE_TEST: -1 + + CROP: + ENABLED: True + SIZE: [1024, 1024] + TYPE: absolute + + GRAYSCALE: + PROBABILITY: 1. + + ADAPTIVE_THRESHOLDING: + PROBABILITY: 1. + + BRIGHTNESS: + PROBABILITY: 1. + MIN_INTENSITY: 0.5 + MAX_INTENSITY: 1.5 + + CONTRAST: + PROBABILITY: 1. + MIN_INTENSITY: 0.5 + MAX_INTENSITY: 1.5 + + SATURATION: + PROBABILITY: 1. + MIN_INTENSITY: 0.5 + MAX_INTENSITY: 1.5 + + HUE: + PROBABILITY: 1. + MIN_DELTA: -0.25 + MAX_DELTA: 0.25 + + INVERT: + PROBABILITY: 1. + + JPEG_COMPRESSION: + PROBABILITY: 1. + MIN_QUALITY: 50 + MAX_QUALITY: 100 + + NOISE: + PROBABILITY: 1. + MIN_STD: 10 + MAX_STD: 32 + + GAUSSIAN_FILTER: + PROBABILITY: 1. + MIN_SIGMA: 0.5 + MAX_SIGMA: 1.5 + + HORIZONTAL_FLIP: + PROBABILITY: 1. + + VERTICAL_FLIP: + PROBABILITY: 1. + + ELASTIC_DEFORMATION: + PROBABILITY: 1. + ALPHA: 0.1 + SIGMA: 0.01 + + AFFINE: + PROBABILITY: 1. + + TRANSLATION: + PROBABILITY: 1. + STANDARD_DEVIATION: 0.02 + + ROTATION: + PROBABILITY: 1. + KAPPA: 30. + + SHEAR: + PROBABILITY: 1. + KAPPA: 20. + + SCALE: + PROBABILITY: 1. + STANDARD_DEVIATION: 0.12 + + ORIENTATION: + PROBABILITY: 1. + PERCENTAGES: (0.25, 0.25, 0.25, 0.25) + +DATALOADER: + NUM_WORKERS: 32 + FILTER_EMPTY_ANNOTATIONS: False + +SOLVER: + IMS_PER_BATCH: 16 + CHECKPOINT_PERIOD: 25000 + BASE_LR: 0.0002 + GAMMA: 0.1 + STEPS: () #(80000, 120000, 160000) + MAX_ITER: 250000 + +MODEL: + MODE: baseline + + SEM_SEG_HEAD: + NUM_CLASSES: 2 + + AMP_TRAIN: + ENABLED: True + + WEIGHTS: + +TRAIN: + WEIGHTS: + +TEST: + WEIGHTS: + EVAL_PERIOD: 10000 diff --git a/data/augmentations.py b/data/augmentations.py index e4ac1f2..ba25d1f 100644 --- a/data/augmentations.py +++ b/data/augmentations.py @@ -4,6 +4,7 @@ import inspect import pprint import sys +import time from pathlib import Path from typing import Optional, Sequence, override @@ -17,13 +18,31 @@ from scipy.ndimage import gaussian_filter sys.path.append(str(Path(__file__).resolve().parent.joinpath(".."))) - from data import numpy_transforms as NT from data import torch_transforms as TT # REVIEW Use the self._init() function +class TimedAugmentationList(T.AugmentationList): + def __init_subclass__(cls) -> None: + super().__init_subclass__() + cls.__call__ = cls._timed(cls.__call__) + + @classmethod + def _timed(cls, func): + def wrapper(*args, **kwargs): + start = time.perf_counter() + result = func(*args, **kwargs) + print(f"{cls.__name__}:{func.__name__} took {time.perf_counter() - start} seconds") + return result + + return wrapper + + +T.AugmentationList = TimedAugmentationList + + class RandomApply(T.RandomApply): """ Randomly apply an augmentation to an image with a given probability. @@ -1879,21 +1898,23 @@ def test(args) -> None: # image = load_image_array_from_path(Path(tmp_dir).joinpath(output["image_paths"]))["image"] # type: ignore # sem_seg = load_image_array_from_path(Path(tmp_dir).joinpath(output["sem_seg_paths"]), mode="grayscale")["image"] # type: ignore - image = load_image_tensor_from_path(Path(tmp_dir).joinpath(output["image_paths"]), device="cuda")["image"] # type: ignore - sem_seg = load_image_tensor_from_path(Path(tmp_dir).joinpath(output["sem_seg_paths"]), mode="grayscale", device="cuda")["image"] # type: ignore + image = load_image_tensor_from_path(Path(tmp_dir).joinpath(output["image_paths"]), device="cpu")["image"] # type: ignore + sem_seg = load_image_tensor_from_path(Path(tmp_dir).joinpath(output["sem_seg_paths"]), mode="grayscale", device="cpu")["image"] # type: ignore - # augs = build_augmentation(cfg, mode="train") - # aug = T.AugmentationList(augs) + augs = build_augmentation(cfg, mode="train") + aug = T.AugmentationList(augs) - augs = [ - RandomCropResize( - crop_type="absolute", crop_size=(1024, 1024), resize_mode="scaling", scale=0.5, target_dpi=300, max_size=-1 - ) - ] + # augs = [ + # RandomCropResize( + # crop_type="absolute", crop_size=(1024, 1024), resize_mode="scaling", scale=0.5, target_dpi=300, max_size=-1 + # ) + # # RandomAffine() + # ] aug = T.AugmentationList(augs) input_image = image.copy() if isinstance(image, np.ndarray) else image.clone() output = AugInput(image=input_image, sem_seg=sem_seg) + print("Running Augmentations") transforms = aug(output) transforms = [t for t in transforms.transforms if not isinstance(t, T.NoOpTransform)] diff --git a/data/numpy_transforms.py b/data/numpy_transforms.py index fcb887d..b9f3b8a 100644 --- a/data/numpy_transforms.py +++ b/data/numpy_transforms.py @@ -1,4 +1,5 @@ import argparse +import time from typing import Optional import cv2 @@ -7,7 +8,27 @@ import shapely.geometry as geometry from scipy.ndimage import gaussian_filter, map_coordinates -# REVIEW Check if there is a benefit for using scipy instead of the standard torchvision + +class TimedTransform(T.Transform): + def __init_subclass__(cls) -> None: + super().__init_subclass__() + cls.apply_image = cls._timed(cls.apply_image) + cls.apply_segmentation = cls._timed(cls.apply_segmentation) + cls.apply_coords = cls._timed(cls.apply_coords) + cls.inverse = cls._timed(cls.inverse) + + @classmethod + def _timed(cls, func): + def wrapper(*args, **kwargs): + start = time.perf_counter() + result = func(*args, **kwargs) + print(f"{cls.__name__}:{func.__name__} took {time.perf_counter() - start} seconds") + return result + + return wrapper + + +T.Transform = TimedTransform class ResizeTransform(T.Transform): diff --git a/data/test.py b/data/test.py new file mode 100644 index 0000000..c7f0472 --- /dev/null +++ b/data/test.py @@ -0,0 +1,80 @@ +_sum = sum( + [ + 5.587800114881247e-05, + 6.416998076019809e-06, + 9.657000191509724e-06, + 0.012764667000737973, + 0.0063344160007545725, + 0.007565762996819103, + 0.00273162400117144, + 0.011208104999241186, + 1.1949996405746788e-06, + 0.00031858100192039274, + 0.00024359000235563144, + 0.0002492499988875352, + 0.00021513100000447594, + 0.00021272400044836104, + 0.0002167509992432315, + 0.0015182800016191322, + 6.990012479946017e-07, + 0.0019864770001731813, + 1.0140029189642519e-06, + 0.0026487370014365297, + 1.1990014172624797e-06, + 0.03411611299816286, + 8.450006134808064e-07, + 0.004043042001285357, + 1.1810006981249899e-06, + 0.004515399999945657, + 6.890004442539066e-07, + 0.0016385679991799407, + 1.0760013537947088e-06, + 0.011471959001937648, + 9.800023690331727e-07, + 0.002451975997246336, + 1.2540003808680922e-06, + ] +) +print(_sum) +print(0.9876395419996697 - _sum) + +_sum = sum( + [ + 2.969799970742315e-05, + 1.7359998309984803e-06, + 4.665998858399689e-06, + 0.008956777001003502, + 0.00044370899922796525, + 0.19733788799931062, + 0.024980511003377615, + 0.03417967600034899, + 1.0799994925037026e-06, + 0.00010624999777064659, + 8.179199721780606e-05, + 9.058800060302019e-05, + 0.0030348259970196523, + 0.00035102599940728396, + 0.0003587179999158252, + 0.010983324998960597, + 6.359987310133874e-07, + 0.004484345998207573, + 7.33998604118824e-07, + 0.02561083100226824, + 9.190007403958589e-07, + 0.007476146998669719, + 3.5150005714967847e-06, + 0.01888903299914091, + 6.330010364763439e-07, + 0.004940410999552114, + 5.299989425111562e-07, + 0.0015438919981534127, + 6.800000846851617e-07, + 0.0031471509973926004, + 7.419985195156187e-07, + 0.007156359002692625, + 1.3349999790079892e-06, + ] +) + +print(_sum) +print(0.49114640400148346 - _sum) diff --git a/data/torch_transforms.py b/data/torch_transforms.py index 126ceb9..d37c842 100644 --- a/data/torch_transforms.py +++ b/data/torch_transforms.py @@ -12,7 +12,9 @@ import torchvision.transforms.functional as F from torchvision.transforms import InterpolationMode -# REVIEW Check if there is a benefit for using scipy instead of the standard torchvision +from data.numpy_transforms import TimedTransform + +T.Transform = TimedTransform class ResizeTransform(T.Transform): @@ -1120,7 +1122,7 @@ def test(args) -> None: ), image.shape[1], image.shape[2], - ).apply_segmentation(torch.zeros([1, 4000, 4000])) + ).apply_segmentation(torch.zeros([1, 4000, 4000], dtype=torch.uint8)) # output_image = GrayscaleTransform().apply_image(image) # output_image = GaussianFilterTransform(sigma=2).apply_image(image) # output_image = BlendTransform(1.0, 0.5, 0.5).apply_image(image) @@ -1128,7 +1130,7 @@ def test(args) -> None: # output_image = AdaptiveThresholdTransform().apply_image(image) # output_image = OrientationTransform(1, image.shape[0], image.shape[1]).apply_image(image) - output_image = output_image.cpu().numpy().transpose(1, 2, 0) + output_image = output_image.cpu().numpy().squeeze(0) im = Image.fromarray(image.cpu().numpy().transpose(1, 2, 0)) im.show("Original")