From 6f186aafa0aa3c87a15d6d4e2b99ff417e6378f7 Mon Sep 17 00:00:00 2001 From: Amir Lashkari Date: Fri, 17 Jul 2020 12:12:05 -0400 Subject: [PATCH] Update Python UA op, AutoContrast Op and UT Updated Validators.py Fixed UA UT Fixed UA UT Fixed PyLint Errors Added aditional changes remove old golden AutoContrast UT file updated Autocontrast python UT Added golden files Fixed issue fixed UT --- .../minddata/dataset/api/python_bindings.cc | 2 +- .../ccsrc/minddata/dataset/api/transforms.cc | 10 +- .../minddata/dataset/include/transforms.h | 8 +- .../dataset/transforms/vision/c_transforms.py | 10 +- .../transforms/vision/py_transforms.py | 13 +- .../transforms/vision/py_transforms_util.py | 6 +- .../dataset/transforms/vision/validators.py | 8 +- .../golden/autcontrast_01_result_c.npz | Bin 0 -> 607 bytes .../golden/autcontrast_01_result_py.npz | Bin 607 -> 607 bytes tests/ut/python/dataset/test_autocontrast.py | 118 ++++++++++++++++-- .../ut/python/dataset/test_uniform_augment.py | 12 +- 11 files changed, 151 insertions(+), 36 deletions(-) create mode 100644 tests/ut/data/dataset/golden/autcontrast_01_result_c.npz diff --git a/mindspore/ccsrc/minddata/dataset/api/python_bindings.cc b/mindspore/ccsrc/minddata/dataset/api/python_bindings.cc index d1405a01d9b..16bdd613c92 100644 --- a/mindspore/ccsrc/minddata/dataset/api/python_bindings.cc +++ b/mindspore/ccsrc/minddata/dataset/api/python_bindings.cc @@ -425,7 +425,7 @@ void bindTensorOps1(py::module *m) { (void)py::class_>( *m, "UniformAugOp", "Tensor operation to apply random augmentation(s).") - .def(py::init>, int32_t>(), py::arg("operations"), + .def(py::init>, int32_t>(), py::arg("transforms"), py::arg("NumOps") = UniformAugOp::kDefNumOps); (void)py::class_>( diff --git a/mindspore/ccsrc/minddata/dataset/api/transforms.cc b/mindspore/ccsrc/minddata/dataset/api/transforms.cc index 59a25ef9f54..008d64caf2f 100644 --- a/mindspore/ccsrc/minddata/dataset/api/transforms.cc +++ b/mindspore/ccsrc/minddata/dataset/api/transforms.cc @@ -90,9 +90,9 @@ std::shared_ptr CenterCrop(std::vector size) { } // Function to create UniformAugOperation. -std::shared_ptr UniformAugment(std::vector> operations, +std::shared_ptr UniformAugment(std::vector> transforms, int32_t num_ops) { - auto op = std::make_shared(operations, num_ops); + auto op = std::make_shared(transforms, num_ops); // Input validation if (!op->ValidateParams()) { return nullptr; @@ -290,14 +290,14 @@ std::shared_ptr CenterCropOperation::Build() { } // UniformAugOperation -UniformAugOperation::UniformAugOperation(std::vector> operations, int32_t num_ops) - : operations_(operations), num_ops_(num_ops) {} +UniformAugOperation::UniformAugOperation(std::vector> transforms, int32_t num_ops) + : transforms_(transforms), num_ops_(num_ops) {} bool UniformAugOperation::ValidateParams() { return true; } std::shared_ptr UniformAugOperation::Build() { std::vector> tensor_ops; - (void)std::transform(operations_.begin(), operations_.end(), std::back_inserter(tensor_ops), + (void)std::transform(transforms_.begin(), transforms_.end(), std::back_inserter(tensor_ops), [](std::shared_ptr op) -> std::shared_ptr { return op->Build(); }); std::shared_ptr tensor_op = std::make_shared(tensor_ops, num_ops_); return tensor_op; diff --git a/mindspore/ccsrc/minddata/dataset/include/transforms.h b/mindspore/ccsrc/minddata/dataset/include/transforms.h index 92fa8b08bf2..76bcc390f21 100644 --- a/mindspore/ccsrc/minddata/dataset/include/transforms.h +++ b/mindspore/ccsrc/minddata/dataset/include/transforms.h @@ -108,10 +108,10 @@ std::shared_ptr CenterCrop(std::vector size); /// \brief Function to create a UniformAugment TensorOperation. /// \notes Tensor operation to perform randomly selected augmentation. -/// \param[in] operations - a vector of TensorOperation operations. +/// \param[in] transforms - a vector of TensorOperation transforms. /// \param[in] num_ops - integer representing the number of OPs to be selected and applied. /// \return Shared pointer to the current TensorOperation. -std::shared_ptr UniformAugment(std::vector> operations, +std::shared_ptr UniformAugment(std::vector> transforms, int32_t num_ops = 2); /// \brief Function to create a RandomHorizontalFlip TensorOperation. @@ -264,7 +264,7 @@ class CenterCropOperation : public TensorOperation { class UniformAugOperation : public TensorOperation { public: - explicit UniformAugOperation(std::vector> operations, int32_t num_ops = 2); + explicit UniformAugOperation(std::vector> transforms, int32_t num_ops = 2); ~UniformAugOperation() = default; @@ -273,7 +273,7 @@ class UniformAugOperation : public TensorOperation { bool ValidateParams() override; private: - std::vector> operations_; + std::vector> transforms_; int32_t num_ops_; }; diff --git a/mindspore/dataset/transforms/vision/c_transforms.py b/mindspore/dataset/transforms/vision/c_transforms.py index ab8071d0ab9..887f2420d32 100644 --- a/mindspore/dataset/transforms/vision/c_transforms.py +++ b/mindspore/dataset/transforms/vision/c_transforms.py @@ -722,7 +722,7 @@ class UniformAugment(cde.UniformAugOp): Tensor operation to perform randomly selected augmentation. Args: - operations: list of C++ operations (python OPs are not accepted). + transforms: list of C++ operations (python OPs are not accepted). num_ops (int, optional): number of OPs to be selected and applied (default=2). Examples: @@ -730,7 +730,7 @@ class UniformAugment(cde.UniformAugOp): >>> c_transforms.RandomVerticalFlip(), >>> c_transforms.RandomColorAdjust(), >>> c_transforms.RandomRotation(degrees=45)] - >>> uni_aug = c_transforms.UniformAugment(operations=transforms_list, num_ops=2) + >>> uni_aug = c_transforms.UniformAugment(transforms=transforms_list, num_ops=2) >>> transforms_all = [c_transforms.Decode(), c_transforms.Resize(size=[224, 224]), >>> uni_aug, F.ToTensor()] >>> ds_ua = ds.map(input_columns="image", @@ -738,10 +738,10 @@ class UniformAugment(cde.UniformAugOp): """ @check_uniform_augment_cpp - def __init__(self, operations, num_ops=2): - self.operations = operations + def __init__(self, transforms, num_ops=2): + self.transforms = transforms self.num_ops = num_ops - super().__init__(operations, num_ops) + super().__init__(transforms, num_ops) class RandomSelectSubpolicy(cde.RandomSelectSubpolicyOp): diff --git a/mindspore/dataset/transforms/vision/py_transforms.py b/mindspore/dataset/transforms/vision/py_transforms.py index 3bfd6b0644f..07630b96cc9 100644 --- a/mindspore/dataset/transforms/vision/py_transforms.py +++ b/mindspore/dataset/transforms/vision/py_transforms.py @@ -33,7 +33,7 @@ from .validators import check_prob, check_crop, check_resize_interpolation, chec check_normalize_py, check_random_crop, check_random_color_adjust, check_random_rotation, \ check_transforms_list, check_random_apply, check_ten_crop, check_num_channels, check_pad, \ check_random_perspective, check_random_erasing, check_cutout, check_linear_transform, check_random_affine, \ - check_mix_up, check_positive_degrees, check_uniform_augment_py, check_compose_list + check_mix_up, check_positive_degrees, check_uniform_augment_py, check_compose_list, check_auto_contrast from .utils import Inter, Border DE_PY_INTER_MODE = {Inter.NEAREST: Image.NEAREST, @@ -1361,6 +1361,10 @@ class AutoContrast: """ Automatically maximize the contrast of the input PIL image. + Args: + cutoff (float, optional): Percent of pixels to cut off from the histogram (default=0.0). + ignore (int or sequence, optional): Pixel values to ignore (default=None). + Examples: >>> py_transforms.ComposeOp([py_transforms.Decode(), >>> py_transforms.AutoContrast(), @@ -1368,6 +1372,11 @@ class AutoContrast: """ + @check_auto_contrast + def __init__(self, cutoff=0.0, ignore=None): + self.cutoff = cutoff + self.ignore = ignore + def __call__(self, img): """ Call method. @@ -1379,7 +1388,7 @@ class AutoContrast: img (PIL Image), Augmented image. """ - return util.auto_contrast(img) + return util.auto_contrast(img, self.cutoff, self.ignore) class Invert: diff --git a/mindspore/dataset/transforms/vision/py_transforms_util.py b/mindspore/dataset/transforms/vision/py_transforms_util.py index d076109ff46..4b270e21f90 100644 --- a/mindspore/dataset/transforms/vision/py_transforms_util.py +++ b/mindspore/dataset/transforms/vision/py_transforms_util.py @@ -1457,13 +1457,15 @@ def random_sharpness(img, degrees): return ImageEnhance.Sharpness(img).enhance(v) -def auto_contrast(img): +def auto_contrast(img, cutoff, ignore): """ Automatically maximize the contrast of the input PIL image. Args: img (PIL Image): Image to be augmented with AutoContrast. + cutoff (float, optional): Percent of pixels to cut off from the histogram (default=0.0). + ignore (int or sequence, optional): Pixel values to ignore (default=None). Returns: img (PIL Image), Augmented image. @@ -1473,7 +1475,7 @@ def auto_contrast(img): if not is_pil(img): raise TypeError('img should be PIL Image. Got {}'.format(type(img))) - return ImageOps.autocontrast(img) + return ImageOps.autocontrast(img, cutoff, ignore) def invert_color(img): diff --git a/mindspore/dataset/transforms/vision/validators.py b/mindspore/dataset/transforms/vision/validators.py index 6a1e693ec8b..d2df82c7791 100644 --- a/mindspore/dataset/transforms/vision/validators.py +++ b/mindspore/dataset/transforms/vision/validators.py @@ -506,13 +506,13 @@ def check_uniform_augment_cpp(method): @wraps(method) def new_method(self, *args, **kwargs): - [operations, num_ops], _ = parse_user_args(method, *args, **kwargs) + [transforms, num_ops], _ = parse_user_args(method, *args, **kwargs) type_check(num_ops, (int,), "num_ops") check_positive(num_ops, "num_ops") - if num_ops > len(operations): - raise ValueError("num_ops is greater than operations list size") - type_check_list(operations, (TensorOp,), "tensor_ops") + if num_ops > len(transforms): + raise ValueError("num_ops is greater than transforms list size") + type_check_list(transforms, (TensorOp,), "tensor_ops") return method(self, *args, **kwargs) diff --git a/tests/ut/data/dataset/golden/autcontrast_01_result_c.npz b/tests/ut/data/dataset/golden/autcontrast_01_result_c.npz new file mode 100644 index 0000000000000000000000000000000000000000..16b8642b9723b89c23e44a3a26525ccfdd96c79d GIT binary patch literal 607 zcmWIWW@Zs#fB;1X6>(kl>x>KxAk4`i!jM>06mOuHS5V2wAOIEwDFjJ^z+}Hr-+)L) zhBAg~^_0}&LuqFrRwFD=9FXt-J4j+6hmH|C&N>KR-XO|3CmHyzNU0d6GI~3wbpnSb_36iAkwBg?zDv{22@x zU>gN8fYu2H6$*i@V`(iE&VZPoW>P2uF<&&OPz+|iO`$ld`3xn65=ouT0=2KqwC&gQ zF-* z&x=3y)d-wh_Fb+}v7}HbDKWLAP&r92z?+dtgc(&_+iVni%xL&$qVlJ6M<3*g$W@$-*S3=_R4ge}N=i&E VDO66<3-D%S5@ANwHCc_x5&*BJ6_@}3 diff --git a/tests/ut/python/dataset/test_autocontrast.py b/tests/ut/python/dataset/test_autocontrast.py index fd390b54832..6c3fc671d7f 100644 --- a/tests/ut/python/dataset/test_autocontrast.py +++ b/tests/ut/python/dataset/test_autocontrast.py @@ -58,7 +58,7 @@ def test_auto_contrast_py(plot=False): transforms_auto_contrast = F.ComposeOp([F.Decode(), F.Resize((224, 224)), - F.AutoContrast(), + F.AutoContrast(cutoff=10.0, ignore=[10, 20]), F.ToTensor()]) ds_auto_contrast = ds.map(input_columns="image", @@ -99,8 +99,8 @@ def test_auto_contrast_c(plot=False): ds = ds.map(input_columns=["image"], operations=[C.Decode(), C.Resize((224, 224))]) - python_op = F.AutoContrast() - c_op = C.AutoContrast() + python_op = F.AutoContrast(cutoff=10.0, ignore=[10, 20]) + c_op = C.AutoContrast(cutoff=10.0, ignore=[10, 20]) transforms_op = F.ComposeOp([lambda img: F.ToPIL()(img.astype(np.uint8)), python_op, np.array])() @@ -143,6 +143,10 @@ def test_auto_contrast_c(plot=False): logger.info("MSE= {}".format(str(np.mean(mse)))) np.testing.assert_equal(np.mean(mse), 0.0) + # Compare with expected md5 from images + filename = "autcontrast_01_result_c.npz" + save_and_check_md5(ds_auto_contrast_c, filename, generate_golden=GENERATE_GOLDEN) + if plot: visualize_list(images_auto_contrast_c, images_auto_contrast_py, visualize_mode=2) @@ -209,11 +213,11 @@ def test_auto_contrast_one_channel_c(plot=False): visualize_list(images_auto_contrast_c, images_auto_contrast_py, visualize_mode=2) -def test_auto_contrast_invalid_input_c(): +def test_auto_contrast_invalid_ignore_param_c(): """ - Test AutoContrast C Op with invalid params + Test AutoContrast C Op with invalid ignore parameter """ - logger.info("Test AutoContrast C Op with invalid params") + logger.info("Test AutoContrast C Op with invalid ignore parameter") try: ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) ds = ds.map(input_columns=["image"], @@ -226,10 +230,110 @@ def test_auto_contrast_invalid_input_c(): except TypeError as error: logger.info("Got an exception in DE: {}".format(str(error))) assert "Argument ignore with value 255.5 is not of type" in str(error) + try: + ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) + ds = ds.map(input_columns=["image"], + operations=[C.Decode(), + C.Resize((224, 224)), + lambda img: np.array(img[:, :, 0])]) + # invalid ignore + ds = ds.map(input_columns="image", + operations=C.AutoContrast(ignore=(10, 100))) + except TypeError as error: + logger.info("Got an exception in DE: {}".format(str(error))) + assert "Argument ignore with value (10,100) is not of type" in str(error) + + +def test_auto_contrast_invalid_cutoff_param_c(): + """ + Test AutoContrast C Op with invalid cutoff parameter + """ + logger.info("Test AutoContrast C Op with invalid cutoff parameter") + try: + ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) + ds = ds.map(input_columns=["image"], + operations=[C.Decode(), + C.Resize((224, 224)), + lambda img: np.array(img[:, :, 0])]) + # invalid ignore + ds = ds.map(input_columns="image", + operations=C.AutoContrast(cutoff=-10.0)) + except ValueError as error: + logger.info("Got an exception in DE: {}".format(str(error))) + assert "Input cutoff is not within the required interval of (0 to 100)." in str(error) + try: + ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) + ds = ds.map(input_columns=["image"], + operations=[C.Decode(), + C.Resize((224, 224)), + lambda img: np.array(img[:, :, 0])]) + # invalid ignore + ds = ds.map(input_columns="image", + operations=C.AutoContrast(cutoff=120.0)) + except ValueError as error: + logger.info("Got an exception in DE: {}".format(str(error))) + assert "Input cutoff is not within the required interval of (0 to 100)." in str(error) + + +def test_auto_contrast_invalid_ignore_param_py(): + """ + Test AutoContrast python Op with invalid ignore parameter + """ + logger.info("Test AutoContrast python Op with invalid ignore parameter") + try: + ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) + ds = ds.map(input_columns=["image"], + operations=[F.ComposeOp([F.Decode(), + F.Resize((224, 224)), + F.AutoContrast(ignore=255.5), + F.ToTensor()])]) + except TypeError as error: + logger.info("Got an exception in DE: {}".format(str(error))) + assert "Argument ignore with value 255.5 is not of type" in str(error) + try: + ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) + ds = ds.map(input_columns=["image"], + operations=[F.ComposeOp([F.Decode(), + F.Resize((224, 224)), + F.AutoContrast(ignore=(10, 100)), + F.ToTensor()])]) + except TypeError as error: + logger.info("Got an exception in DE: {}".format(str(error))) + assert "Argument ignore with value (10,100) is not of type" in str(error) + + +def test_auto_contrast_invalid_cutoff_param_py(): + """ + Test AutoContrast python Op with invalid cutoff parameter + """ + logger.info("Test AutoContrast python Op with invalid cutoff parameter") + try: + ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) + ds = ds.map(input_columns=["image"], + operations=[F.ComposeOp([F.Decode(), + F.Resize((224, 224)), + F.AutoContrast(cutoff=-10.0), + F.ToTensor()])]) + except ValueError as error: + logger.info("Got an exception in DE: {}".format(str(error))) + assert "Input cutoff is not within the required interval of (0 to 100)." in str(error) + try: + ds = de.ImageFolderDatasetV2(dataset_dir=DATA_DIR, shuffle=False) + ds = ds.map(input_columns=["image"], + operations=[F.ComposeOp([F.Decode(), + F.Resize((224, 224)), + F.AutoContrast(cutoff=120.0), + F.ToTensor()])]) + except ValueError as error: + logger.info("Got an exception in DE: {}".format(str(error))) + assert "Input cutoff is not within the required interval of (0 to 100)." in str(error) if __name__ == "__main__": test_auto_contrast_py(plot=True) test_auto_contrast_c(plot=True) test_auto_contrast_one_channel_c(plot=True) - test_auto_contrast_invalid_input_c() + test_auto_contrast_invalid_ignore_param_c() + test_auto_contrast_invalid_ignore_param_py() + test_auto_contrast_invalid_cutoff_param_c() + test_auto_contrast_invalid_cutoff_param_py() diff --git a/tests/ut/python/dataset/test_uniform_augment.py b/tests/ut/python/dataset/test_uniform_augment.py index c0047226830..a52da41e206 100644 --- a/tests/ut/python/dataset/test_uniform_augment.py +++ b/tests/ut/python/dataset/test_uniform_augment.py @@ -124,7 +124,7 @@ def test_cpp_uniform_augment(plot=False, num_ops=2): C.RandomColorAdjust(), C.RandomRotation(degrees=45)] - uni_aug = C.UniformAugment(operations=transforms_ua, num_ops=num_ops) + uni_aug = C.UniformAugment(transforms=transforms_ua, num_ops=num_ops) transforms_all = [C.Decode(), C.Resize(size=[224, 224]), uni_aug, @@ -166,7 +166,7 @@ def test_cpp_uniform_augment_exception_pyops(num_ops=2): F.Invert()] with pytest.raises(TypeError) as e: - C.UniformAugment(operations=transforms_ua, num_ops=num_ops) + C.UniformAugment(transforms=transforms_ua, num_ops=num_ops) logger.info("Got an exception in DE: {}".format(str(e))) assert "Argument tensor_ops[5] with value" \ @@ -187,7 +187,7 @@ def test_cpp_uniform_augment_exception_large_numops(num_ops=6): C.RandomRotation(degrees=45)] try: - _ = C.UniformAugment(operations=transforms_ua, num_ops=num_ops) + _ = C.UniformAugment(transforms=transforms_ua, num_ops=num_ops) except Exception as e: logger.info("Got an exception in DE: {}".format(str(e))) @@ -207,7 +207,7 @@ def test_cpp_uniform_augment_exception_nonpositive_numops(num_ops=0): C.RandomRotation(degrees=45)] try: - _ = C.UniformAugment(operations=transforms_ua, num_ops=num_ops) + _ = C.UniformAugment(transforms=transforms_ua, num_ops=num_ops) except Exception as e: logger.info("Got an exception in DE: {}".format(str(e))) @@ -227,7 +227,7 @@ def test_cpp_uniform_augment_exception_float_numops(num_ops=2.5): C.RandomRotation(degrees=45)] try: - _ = C.UniformAugment(operations=transforms_ua, num_ops=num_ops) + _ = C.UniformAugment(transforms=transforms_ua, num_ops=num_ops) except Exception as e: logger.info("Got an exception in DE: {}".format(str(e))) @@ -248,7 +248,7 @@ def test_cpp_uniform_augment_random_crop_badinput(num_ops=1): C.RandomCrop(size=[224, 224]), C.RandomHorizontalFlip() ] - uni_aug = C.UniformAugment(operations=transforms_ua, num_ops=num_ops) + uni_aug = C.UniformAugment(transforms=transforms_ua, num_ops=num_ops) ds1 = ds1.map(input_columns="image", operations=uni_aug) # apply DatasetOps