From b207f1d308ade6e0471693dd9a82dd4ec69c18bb Mon Sep 17 00:00:00 2001 From: Jasonlee1995 <2014145110@yonsei.ac.kr> Date: Wed, 16 Feb 2022 15:28:44 +0900 Subject: [PATCH 1/3] Add color jitter augmentation Not include hue --- ffcv/transforms/random_jitter.py | 144 +++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 ffcv/transforms/random_jitter.py diff --git a/ffcv/transforms/random_jitter.py b/ffcv/transforms/random_jitter.py new file mode 100644 index 00000000..a71fbdd4 --- /dev/null +++ b/ffcv/transforms/random_jitter.py @@ -0,0 +1,144 @@ +''' +Random color operations similar to torchvision.transforms.ColorJitter except not supporting hue +Reference : https://github.com/pytorch/vision/blob/main/torchvision/transforms/functional_tensor.py +''' + +import numpy as np + +from dataclasses import replace +from ..pipeline.allocation_query import AllocationQuery +from ..pipeline.operation import Operation +from ..pipeline.state import State +from ..pipeline.compiler import Compiler + + + +class RandomBrightness(Operation): + ''' + Randomly adjust image brightness. Operates on raw arrays (not tensors). + + Parameters + ---------- + magnitude : float + randomly choose brightness enhancement factor on [max(0, 1-magnitude), 1+magnitude] + p : float + probability to apply brightness + ''' + def __init__(self, magnitude: float, p=0.5): + super().__init__() + self.p = p + self.magnitude = magnitude + + def generate_code(self): + my_range = Compiler.get_iterator() + p = self.p + magnitude = self.magnitude + + def brightness(images, dst): + def blend(img1, img2, ratio): return (ratio*img1 + (1-ratio)*img2).clip(0, 255).astype(img1.dtype) + + apply_bright = np.random.rand(images.shape[0]) < p + magnitudes = np.random.uniform(max(0, 1-magnitude), 1+magnitude, images.shape[0]) + for i in my_range(images.shape[0]): + if apply_bright[i]: + dst[i] = blend(images[i], 0, magnitudes[i]) + else: + dst[i] = images[i] + + return dst + + brightness.is_parallel = True + return brightness + + def declare_state_and_memory(self, previous_state): + return (replace(previous_state, jit_mode=True), AllocationQuery(previous_state.shape, previous_state.dtype)) + + + +class RandomContrast(Operation): + ''' + Randomly adjust image contrast. Operates on raw arrays (not tensors). + + Parameters + ---------- + magnitude : float + randomly choose contrast enhancement factor on [max(0, 1-magnitude), 1+magnitude] + p : float + probability to apply contrast + ''' + def __init__(self, magnitude, p=0.5): + super().__init__() + self.p = p + self.magnitude = magnitude + + def generate_code(self): + my_range = Compiler.get_iterator() + p = self.p + magnitude = self.magnitude + + def contrast(images, dst): + def blend(img1, img2, ratio): return (ratio*img1 + (1-ratio)*img2).clip(0, 255).astype(img1.dtype) + + apply_contrast = np.random.rand(images.shape[0]) < p + magnitudes = np.random.uniform(max(0, 1-magnitude), 1+magnitude, images.shape[0]) + for i in my_range(images.shape[0]): + if apply_contrast[i]: + r, g, b = images[i,:,:,0], images[i,:,:,1], images[i,:,:,2] + l_img = (0.2989 * r + 0.587 * g + 0.114 * b).astype(images[i].dtype) + dst[i] = blend(images[i], l_img.mean(), magnitudes[i]) + else: + dst[i] = images[i] + return dst + + contrast.is_parallel = True + return contrast + + def declare_state_and_memory(self, previous_state): + return (replace(previous_state, jit_mode=True), AllocationQuery(previous_state.shape, previous_state.dtype)) + + + +class RandomSaturation(Operation): + ''' + Randomly adjust image color balance. Operates on raw arrays (not tensors). + + Parameters + ---------- + magnitude : float + randomly choose color balance enhancement factor on [max(0, 1-magnitude), 1+magnitude] + p : float + probability to apply saturation + ''' + def __init__(self, magnitude, p=0.5): + super().__init__() + self.p = p + self.magnitude = magnitude + + def generate_code(self): + my_range = Compiler.get_iterator() + p = self.p + magnitude = self.magnitude + + def saturation(images, dst): + def blend(img1, img2, ratio): return (ratio*img1 + (1-ratio)*img2).clip(0, 255).astype(img1.dtype) + + apply_saturation = np.random.rand(images.shape[0]) < p + magnitudes = np.random.uniform(max(0, 1-magnitude), 1+magnitude, images.shape[0]) + for i in my_range(images.shape[0]): + if apply_saturation[i]: + r, g, b = images[i,:,:,0], images[i,:,:,1], images[i,:,:,2] + l_img = (0.2989 * r + 0.587 * g + 0.114 * b).astype(images[i].dtype) + l_img3 = np.zeros_like(images[i]) + for j in my_range(images[i].shape[-1]): + l_img3[:,:,j] = l_img + dst[i] = blend(images[i], l_img3, magnitudes[i]) + else: + dst[i] = images[i] + + return dst + + saturation.is_parallel = True + return saturation + + def declare_state_and_memory(self, previous_state): + return (replace(previous_state, jit_mode=True), AllocationQuery(previous_state.shape, previous_state.dtype)) From 71eb9f3900243f5614514c486615314b9823b5d1 Mon Sep 17 00:00:00 2001 From: Jasonlee1995 <2014145110@yonsei.ac.kr> Date: Wed, 16 Feb 2022 16:26:59 +0900 Subject: [PATCH 2/3] Apply on init --- ffcv/transforms/__init__.py | 4 +++- ffcv/transforms/{random_jitter.py => color_jitter.py} | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename ffcv/transforms/{random_jitter.py => color_jitter.py} (100%) diff --git a/ffcv/transforms/__init__.py b/ffcv/transforms/__init__.py index bc8fa321..2636a447 100644 --- a/ffcv/transforms/__init__.py +++ b/ffcv/transforms/__init__.py @@ -9,6 +9,7 @@ from .translate import RandomTranslate from .mixup import ImageMixup, LabelMixup, MixupToOneHot from .module import ModuleWrapper +from .color_jitter import RandomBrightness, RandomContrast, RandomSaturation __all__ = ['ToTensor', 'ToDevice', 'ToTorchImage', 'NormalizeImage', @@ -16,4 +17,5 @@ 'RandomResizedCrop', 'RandomHorizontalFlip', 'RandomTranslate', 'Cutout', 'ImageMixup', 'LabelMixup', 'MixupToOneHot', 'Poison', 'ReplaceLabel', - 'ModuleWrapper'] \ No newline at end of file + 'ModuleWrapper', + 'RandomBrightness', 'RandomContrast', 'RandomSaturation'] diff --git a/ffcv/transforms/random_jitter.py b/ffcv/transforms/color_jitter.py similarity index 100% rename from ffcv/transforms/random_jitter.py rename to ffcv/transforms/color_jitter.py From c2c8ccf927b77b9287ed4b2f1541f4e830ba4b65 Mon Sep 17 00:00:00 2001 From: Jasonlee1995 <2014145110@yonsei.ac.kr> Date: Thu, 17 Feb 2022 18:07:32 +0900 Subject: [PATCH 3/3] Outplace to Inplace --- ffcv/.DS_Store | Bin 0 -> 6148 bytes ffcv/transforms/color_jitter.py | 25 ++++++++++--------------- 2 files changed, 10 insertions(+), 15 deletions(-) create mode 100644 ffcv/.DS_Store diff --git a/ffcv/.DS_Store b/ffcv/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f1fad9b32e4ff8d8848ef21e5451c2ae2fbacdc2 GIT binary patch literal 6148 zcmeHK%}xR_5S{|cA~D&6CVFe)l|&E{4qi5hFW?$IsKMQUx^dYWc98=i*}J}wFXHn! z(-sl}9=sSMGs*O8=VzOK-E>+25S?+q0pJ3FgGyMaV6#TZPr4!nYatZ+8!0@1f)NZM zU5RGHUu1yxZU-{lvj7s@wZ;C0lk_EwRfztN@FkAYtX}^Vg<@%IyX=&ms&nT*sfnKj z**NV4qZ=AsDiw$Geh^+ogGtZbJ5xy(M9E;J6QceALvF95q^~9&HBS1e&h?GMsW_FM zdpMmoPTDouY_?`KIc+ps^_pzA>$6$K**`iyz34s1!$iFqMg{(ST6QhY;T=0`7x(Iq zl2|2==%44#a~PQcW`G&k00!*Q=TtXft-M5LfEoB119Uz}R6@^UZcrZ`*wFQn{3SvX z?9*F