From 415216cdea093b9b9c2f655be5cb93ddd853145a Mon Sep 17 00:00:00 2001 From: yaox12 Date: Mon, 16 Jul 2018 17:48:23 +0800 Subject: [PATCH 1/5] ColorJitter Enhancement --- torchvision/transforms/transforms.py | 61 ++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/torchvision/transforms/transforms.py b/torchvision/transforms/transforms.py index fcba9dcd6bd..53af60a47f3 100644 --- a/torchvision/transforms/transforms.py +++ b/torchvision/transforms/transforms.py @@ -728,14 +728,18 @@ class ColorJitter(object): """Randomly change the brightness, contrast and saturation of an image. Args: - brightness (float): How much to jitter brightness. brightness_factor - is chosen uniformly from [max(0, 1 - brightness), 1 + brightness]. - contrast (float): How much to jitter contrast. contrast_factor - is chosen uniformly from [max(0, 1 - contrast), 1 + contrast]. - saturation (float): How much to jitter saturation. saturation_factor - is chosen uniformly from [max(0, 1 - saturation), 1 + saturation]. - hue(float): How much to jitter hue. hue_factor is chosen uniformly from - [-hue, hue]. Should be >=0 and <= 0.5. + brightness (float or tuple of float (min, max)): How much to jitter brightness. + brightness_factor is chosen uniformly from [max(0, 1 - brightness), 1 + brightness] + or the given [min, max]. Should be non negative numbers. + contrast (float or tuple of float (min, max)): How much to jitter contrast. + contrast_factor is chosen uniformly from [max(0, 1 - contrast), 1 + contrast] + or the given [min, max]. Should be non negative numbers. + saturation (float or tuple of float (min, max)): How much to jitter saturation. + saturation_factor is chosen uniformly from [max(0, 1 - saturation), 1 + saturation] + or the given [min, max]. Should be non negative numbers. + hue (float or tuple of float (min, max)): How much to jitter hue. + hue_factor is chosen uniformly from [-hue, hue] or the given [min, max]. + Should have 0<= hue <= 0.5 or -0.5 <= min <= max <= 0.5. """ def __init__(self, brightness=0, contrast=0, saturation=0, hue=0): self.brightness = brightness @@ -754,20 +758,53 @@ def get_params(brightness, contrast, saturation, hue): saturation in a random order. """ transforms = [] - if brightness > 0: + brightness_factor = None + if isinstance(brightness, float) and brightness >= 0: brightness_factor = random.uniform(max(0, 1 - brightness), 1 + brightness) + elif isinstance(brightness, tuple) and len(brightness) == 2: + if not (0 <= brightness[0] <= brightness[1]): + raise ValueError('Invalid brightness factor {}.'.format(brightness)) + brightness_factor = random.uniform(brightness[0], brightness[1]) + else: + raise TypeError('Brightness should be non negative float or tuple of float (min, max).') + if brightness_factor is not None: transforms.append(Lambda(lambda img: F.adjust_brightness(img, brightness_factor))) - if contrast > 0: + contrast_factor = None + if isinstance(contrast, float) and contrast >= 0: contrast_factor = random.uniform(max(0, 1 - contrast), 1 + contrast) + elif isinstance(contrast, tuple) and len(contrast) == 2: + if not (0 <= contrast[0] <= contrast[1]): + raise ValueError('Invalid contrast factor {}.'.format(contrast)) + contrast_factor = random.uniform(contrast[0], contrast[1]) + else: + raise TypeError('Contrast should be non negative float or tuple of float (min, max).') + if contrast_factor is not None: transforms.append(Lambda(lambda img: F.adjust_contrast(img, contrast_factor))) - if saturation > 0: + saturation_factor = None + if isinstance(saturation, float) and saturation >= 0: saturation_factor = random.uniform(max(0, 1 - saturation), 1 + saturation) + elif isinstance(saturation, tuple) and len(saturation) == 2: + if not (0 <= saturation[0] <= saturation[1]): + raise ValueError('Invalid saturation factor {}.'.format(saturation)) + saturation_factor = random.uniform(saturation[0], saturation[1]) + else: + raise TypeError('Saturation should be non negative float or tuple of float (min, max).') + if saturation_factor is not None: transforms.append(Lambda(lambda img: F.adjust_saturation(img, saturation_factor))) - if hue > 0: + # hue factor will be check in F.adjust_hue + hue_factor = None + if isinstance(hue, float) and hue >= 0: hue_factor = random.uniform(-hue, hue) + elif isinstance(hue, tuple) and len(hue) == 2: + if not (-0.5 <= hue[0] <= hue[1] <= 0.5): + raise ValueError('Invalid hue factor {}.'.format(hue)) + hue_factor = random.uniform(hue[0], hue[1]) + else: + raise TypeError('Hue should be non negative float or tuple of float (min, max).') + if hue_factor is not None: transforms.append(Lambda(lambda img: F.adjust_hue(img, hue_factor))) random.shuffle(transforms) From 164637e6d383cb60666ebd94169fcc2659d73d9d Mon Sep 17 00:00:00 2001 From: yaox12 Date: Mon, 16 Jul 2018 18:35:57 +0800 Subject: [PATCH 2/5] reduce redundancy --- torchvision/transforms/transforms.py | 57 ++++++++++------------------ 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/torchvision/transforms/transforms.py b/torchvision/transforms/transforms.py index 53af60a47f3..afb410d97a9 100644 --- a/torchvision/transforms/transforms.py +++ b/torchvision/transforms/transforms.py @@ -757,53 +757,38 @@ def get_params(brightness, contrast, saturation, hue): Transform which randomly adjusts brightness, contrast and saturation in a random order. """ + def _sample_from(value, name): + factor = None + if isinstance(value, numbers.Number) and value >= 0: + if name == 'hue': + factor = random.uniform(-value, value) + else: + factor = random.uniform(max(0, 1 - value), 1 + value) + elif isinstance(value, (tuple, list)) and len(value) == 2: + if (name == 'hue' and not (-0.5 <= value[0] <= value[1] <= 0.5)) or \ + (name != 'hue' and not (0 <= value[0] <= value[1])): + raise ValueError('Invalid {} factor {}.'.format(name, value)) + factor = random.uniform(value[0], value[1]) + else: + raise TypeError('{} should be non negative float or tuple of float (min, max).'.format(name)) + return factor + transforms = [] - brightness_factor = None - if isinstance(brightness, float) and brightness >= 0: - brightness_factor = random.uniform(max(0, 1 - brightness), 1 + brightness) - elif isinstance(brightness, tuple) and len(brightness) == 2: - if not (0 <= brightness[0] <= brightness[1]): - raise ValueError('Invalid brightness factor {}.'.format(brightness)) - brightness_factor = random.uniform(brightness[0], brightness[1]) - else: - raise TypeError('Brightness should be non negative float or tuple of float (min, max).') + + brightness_factor = _sample_from(brightness, 'brightness') if brightness_factor is not None: transforms.append(Lambda(lambda img: F.adjust_brightness(img, brightness_factor))) - contrast_factor = None - if isinstance(contrast, float) and contrast >= 0: - contrast_factor = random.uniform(max(0, 1 - contrast), 1 + contrast) - elif isinstance(contrast, tuple) and len(contrast) == 2: - if not (0 <= contrast[0] <= contrast[1]): - raise ValueError('Invalid contrast factor {}.'.format(contrast)) - contrast_factor = random.uniform(contrast[0], contrast[1]) - else: - raise TypeError('Contrast should be non negative float or tuple of float (min, max).') + contrast_factor = _sample_from(contrast, 'contrast') if contrast_factor is not None: transforms.append(Lambda(lambda img: F.adjust_contrast(img, contrast_factor))) - saturation_factor = None - if isinstance(saturation, float) and saturation >= 0: - saturation_factor = random.uniform(max(0, 1 - saturation), 1 + saturation) - elif isinstance(saturation, tuple) and len(saturation) == 2: - if not (0 <= saturation[0] <= saturation[1]): - raise ValueError('Invalid saturation factor {}.'.format(saturation)) - saturation_factor = random.uniform(saturation[0], saturation[1]) - else: - raise TypeError('Saturation should be non negative float or tuple of float (min, max).') + saturation_factor = _sample_from(saturation, 'saturation') if saturation_factor is not None: transforms.append(Lambda(lambda img: F.adjust_saturation(img, saturation_factor))) # hue factor will be check in F.adjust_hue - hue_factor = None - if isinstance(hue, float) and hue >= 0: - hue_factor = random.uniform(-hue, hue) - elif isinstance(hue, tuple) and len(hue) == 2: - if not (-0.5 <= hue[0] <= hue[1] <= 0.5): - raise ValueError('Invalid hue factor {}.'.format(hue)) - hue_factor = random.uniform(hue[0], hue[1]) - else: - raise TypeError('Hue should be non negative float or tuple of float (min, max).') + hue_factor = _sample_from(hue, 'hue') if hue_factor is not None: transforms.append(Lambda(lambda img: F.adjust_hue(img, hue_factor))) From 2ab7d03150685ed30a7b4aafb12e2f65228f5346 Mon Sep 17 00:00:00 2001 From: yaox12 Date: Tue, 17 Jul 2018 00:11:31 +0800 Subject: [PATCH 3/5] improve functional --- torchvision/transforms/transforms.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/torchvision/transforms/transforms.py b/torchvision/transforms/transforms.py index afb410d97a9..45ecc6cc205 100644 --- a/torchvision/transforms/transforms.py +++ b/torchvision/transforms/transforms.py @@ -757,20 +757,22 @@ def get_params(brightness, contrast, saturation, hue): Transform which randomly adjusts brightness, contrast and saturation in a random order. """ - def _sample_from(value, name): + def _sample_from(value, name, center=1, clip_first_on_zero=True): factor = None if isinstance(value, numbers.Number) and value >= 0: - if name == 'hue': - factor = random.uniform(-value, value) - else: - factor = random.uniform(max(0, 1 - value), 1 + value) + value = [center - value, center + value] elif isinstance(value, (tuple, list)) and len(value) == 2: - if (name == 'hue' and not (-0.5 <= value[0] <= value[1] <= 0.5)) or \ - (name != 'hue' and not (0 <= value[0] <= value[1])): + # hue factor will be check in F.adjust_hue + if name != 'hue' and not (0 <= value[0] <= value[1]): raise ValueError('Invalid {} factor {}.'.format(name, value)) - factor = random.uniform(value[0], value[1]) else: raise TypeError('{} should be non negative float or tuple of float (min, max).'.format(name)) + if clip_first_on_zero: + value[0] = max(value[0], 0) + # if brightness/contrast/saturation is 0 or (1, 1) + # hue is 0 or (0, 0), return None, nothing to do. + if not value[0] == value[1] == center: + factor = random.uniform(value[0], value[1]) return factor transforms = [] @@ -787,8 +789,7 @@ def _sample_from(value, name): if saturation_factor is not None: transforms.append(Lambda(lambda img: F.adjust_saturation(img, saturation_factor))) - # hue factor will be check in F.adjust_hue - hue_factor = _sample_from(hue, 'hue') + hue_factor = _sample_from(hue, 'hue', center=0, clip_first_on_zero=False) if hue_factor is not None: transforms.append(Lambda(lambda img: F.adjust_hue(img, hue_factor))) From 37ba17358b69c063f2966429b1da21eb47a6e9c2 Mon Sep 17 00:00:00 2001 From: yaox12 Date: Tue, 17 Jul 2018 10:17:16 +0800 Subject: [PATCH 4/5] check input in init --- torchvision/transforms/transforms.py | 62 ++++++++++++++-------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/torchvision/transforms/transforms.py b/torchvision/transforms/transforms.py index 45ecc6cc205..63a737c5f55 100644 --- a/torchvision/transforms/transforms.py +++ b/torchvision/transforms/transforms.py @@ -742,10 +742,30 @@ class ColorJitter(object): Should have 0<= hue <= 0.5 or -0.5 <= min <= max <= 0.5. """ def __init__(self, brightness=0, contrast=0, saturation=0, hue=0): - self.brightness = brightness - self.contrast = contrast - self.saturation = saturation - self.hue = hue + self.brightness = self._check_input(brightness, 'brightness') + self.contrast = self._check_input(contrast, 'contrast') + self.saturation = self._check_input(saturation, 'saturation') + self.hue = self._check_input(hue, 'hue', center=0, bound=(-0.5, 0.5), + clip_first_on_zero=False) + + def _check_input(self, value, name, center=1, bound=(0, float('inf')), clip_first_on_zero=True): + if isinstance(value, numbers.Number): + if value < 0: + raise ValueError("If {} is a single number, it must be non negative.".format(name)) + value = (center - value, center + value) + if clip_first_on_zero: + value[0] = max(value[0], 0) + elif isinstance(value, (tuple, list)) and len(value) == 2: + if not bound[0] <= value[0] <= value[1] <= bound[1]: + raise ValueError("{} values should be between {}".format(name, bound)) + else: + raise TypeError("{} should be a single number or a list/tuple with lenght 2.".format(name)) + + # if value is 0 or (1., 1.) for brightness/contrast/saturation + # or (0., 0.) for hue, do nothing + if value[0] == value[1] == center: + value = None + return value @staticmethod def get_params(brightness, contrast, saturation, hue): @@ -757,40 +777,22 @@ def get_params(brightness, contrast, saturation, hue): Transform which randomly adjusts brightness, contrast and saturation in a random order. """ - def _sample_from(value, name, center=1, clip_first_on_zero=True): - factor = None - if isinstance(value, numbers.Number) and value >= 0: - value = [center - value, center + value] - elif isinstance(value, (tuple, list)) and len(value) == 2: - # hue factor will be check in F.adjust_hue - if name != 'hue' and not (0 <= value[0] <= value[1]): - raise ValueError('Invalid {} factor {}.'.format(name, value)) - else: - raise TypeError('{} should be non negative float or tuple of float (min, max).'.format(name)) - if clip_first_on_zero: - value[0] = max(value[0], 0) - # if brightness/contrast/saturation is 0 or (1, 1) - # hue is 0 or (0, 0), return None, nothing to do. - if not value[0] == value[1] == center: - factor = random.uniform(value[0], value[1]) - return factor - transforms = [] - brightness_factor = _sample_from(brightness, 'brightness') - if brightness_factor is not None: + if brightness is not None: + brightness_factor = random.uniform(brightness[0], brightness[1]) transforms.append(Lambda(lambda img: F.adjust_brightness(img, brightness_factor))) - contrast_factor = _sample_from(contrast, 'contrast') - if contrast_factor is not None: + if contrast is not None: + contrast_factor = random.uniform(contrast[0], contrast[1]) transforms.append(Lambda(lambda img: F.adjust_contrast(img, contrast_factor))) - saturation_factor = _sample_from(saturation, 'saturation') - if saturation_factor is not None: + if saturation is not None: + saturation_factor = random.uniform(saturation[0], saturation[1]) transforms.append(Lambda(lambda img: F.adjust_saturation(img, saturation_factor))) - hue_factor = _sample_from(hue, 'hue', center=0, clip_first_on_zero=False) - if hue_factor is not None: + if hue is not None: + hue_factor = random.uniform(hue[0], hue[1]) transforms.append(Lambda(lambda img: F.adjust_hue(img, hue_factor))) random.shuffle(transforms) From 3e5a014d19e0eb953fa88bcf62dda2e17fcfe188 Mon Sep 17 00:00:00 2001 From: yaox12 Date: Tue, 17 Jul 2018 11:05:51 +0800 Subject: [PATCH 5/5] fix ci fail --- torchvision/transforms/transforms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/torchvision/transforms/transforms.py b/torchvision/transforms/transforms.py index 63a737c5f55..27616e5515f 100644 --- a/torchvision/transforms/transforms.py +++ b/torchvision/transforms/transforms.py @@ -737,7 +737,7 @@ class ColorJitter(object): saturation (float or tuple of float (min, max)): How much to jitter saturation. saturation_factor is chosen uniformly from [max(0, 1 - saturation), 1 + saturation] or the given [min, max]. Should be non negative numbers. - hue (float or tuple of float (min, max)): How much to jitter hue. + hue (float or tuple of float (min, max)): How much to jitter hue. hue_factor is chosen uniformly from [-hue, hue] or the given [min, max]. Should have 0<= hue <= 0.5 or -0.5 <= min <= max <= 0.5. """ @@ -752,7 +752,7 @@ def _check_input(self, value, name, center=1, bound=(0, float('inf')), clip_firs if isinstance(value, numbers.Number): if value < 0: raise ValueError("If {} is a single number, it must be non negative.".format(name)) - value = (center - value, center + value) + value = [center - value, center + value] if clip_first_on_zero: value[0] = max(value[0], 0) elif isinstance(value, (tuple, list)) and len(value) == 2: