From 2f1f0c438d553fbdc201c5016a1d5ebd3fb23335 Mon Sep 17 00:00:00 2001 From: Cathy Wong Date: Tue, 23 Feb 2021 21:18:04 -0500 Subject: [PATCH] dataset: C++ API Vision support for Ops with TensorTransform op input plus UTs --- .../ccsrc/minddata/dataset/api/vision.cc | 102 ++++-- .../ccsrc/minddata/dataset/include/vision.h | 44 ++- .../minddata/dataset/kernels/ir/validators.h | 3 + tests/ut/cpp/dataset/CMakeLists.txt | 1 + tests/ut/cpp/dataset/c_api_affine_test.cc | 4 +- .../c_api_vision_bounding_box_augment_test.cc | 196 +++++++++-- ...api_vision_random_subselect_policy_test.cc | 324 ++++++++++++++++-- .../dataset/c_api_vision_uniform_aug_test.cc | 253 +++++++++++--- tests/ut/cpp/dataset/common/common.h | 18 + tests/ut/cpp/dataset/ir_vision_test.cc | 95 +++++ 10 files changed, 906 insertions(+), 134 deletions(-) create mode 100644 tests/ut/cpp/dataset/ir_vision_test.cc diff --git a/mindspore/ccsrc/minddata/dataset/api/vision.cc b/mindspore/ccsrc/minddata/dataset/api/vision.cc index c435077566..b2c07bce30 100644 --- a/mindspore/ccsrc/minddata/dataset/api/vision.cc +++ b/mindspore/ccsrc/minddata/dataset/api/vision.cc @@ -39,7 +39,7 @@ namespace dataset { // Transform operations for computer vision. namespace vision { #ifndef ENABLE_ANDROID -// FUNCTIONS TO CREATE VISION TRANSFORM OPERATIONS +// CONSTRUCTORS FOR API CLASSES TO CREATE VISION TENSOR TRANSFORM OPERATIONS // (In alphabetical order) Affine::Affine(float_t degrees, const std::vector &translation, float scale, const std::vector &shear, @@ -63,16 +63,23 @@ std::shared_ptr AutoContrast::Parse() { } // BoundingBoxAugment Transform Operation. -BoundingBoxAugment::BoundingBoxAugment(std::shared_ptr transform, float ratio) { - // Convert transform from TensorTransform to TensorOperation - transform_ = transform->Parse(); - ratio_ = ratio; +BoundingBoxAugment::BoundingBoxAugment(TensorTransform *transform, float ratio) : ratio_(ratio) { + transform_ = transform ? transform->Parse() : nullptr; +} + +BoundingBoxAugment::BoundingBoxAugment(const std::shared_ptr &transform, float ratio) : ratio_(ratio) { + transform_ = transform ? transform->Parse() : nullptr; +} + +BoundingBoxAugment::BoundingBoxAugment(const std::reference_wrapper transform, float ratio) + : ratio_(ratio) { + transform_ = transform.get().Parse(); } std::shared_ptr BoundingBoxAugment::Parse() { return std::make_shared(transform_, ratio_); } -#endif +#endif // not ENABLE_ANDROID // CenterCrop Transform Operation. CenterCrop::CenterCrop(std::vector size) : size_(size) {} @@ -86,7 +93,7 @@ std::shared_ptr CenterCrop::Parse(const MapTargetDevice &env) { usize_.reserve(size_.size()); std::transform(size_.begin(), size_.end(), std::back_inserter(usize_), [](int32_t i) { return (uint32_t)i; }); return std::make_shared(usize_); -#endif +#endif // ENABLE_ACL } return std::make_shared(size_); } @@ -109,6 +116,7 @@ std::shared_ptr CutMixBatch::Parse() { CutOut::CutOut(int32_t length, int32_t num_patches) : length_(length), num_patches_(num_patches) {} std::shared_ptr CutOut::Parse() { return std::make_shared(length_, num_patches_); } +#endif // not ENABLE_ANDROID // Decode Transform Operation. Decode::Decode(bool rgb) : rgb_(rgb) {} @@ -118,13 +126,11 @@ std::shared_ptr Decode::Parse(const MapTargetDevice &env) { if (env == MapTargetDevice::kAscend310) { #ifdef ENABLE_ACL return std::make_shared(); -#endif +#endif // ENABLE_ACL } return std::make_shared(rgb_); } -#endif - #ifdef ENABLE_ACL // DvppDecodeResize Transform Operation. DvppDecodeResizeJpeg::DvppDecodeResizeJpeg(std::vector resize) : resize_(resize) {} @@ -157,7 +163,7 @@ std::shared_ptr DvppDecodePng::Parse() { return std::make_share std::shared_ptr DvppDecodePng::Parse(const MapTargetDevice &env) { return std::make_shared(); } -#endif +#endif // ENABLE_ACL #ifndef ENABLE_ANDROID // Equalize Transform Operation. @@ -178,7 +184,7 @@ std::shared_ptr Invert::Parse() { return std::make_shared MixUpBatch::Parse() { return std::make_shared(alpha_); } -#endif +#endif // not ENABLE_ANDROID // Normalize Transform Operation. Normalize::Normalize(std::vector mean, std::vector std) : mean_(mean), std_(std) {} @@ -333,10 +339,49 @@ std::shared_ptr RandomRotation::Parse() { } // RandomSelectSubpolicy Transform Operation. -// FIXME - Provide TensorTransform support for policy +RandomSelectSubpolicy::RandomSelectSubpolicy(std::vector>> policy) { + for (int32_t i = 0; i < policy.size(); i++) { + std::vector, double>> subpolicy; + + for (int32_t j = 0; j < policy[i].size(); j++) { + TensorTransform *op = policy[i][j].first; + std::shared_ptr operation = (op ? op->Parse() : nullptr); + double prob = policy[i][j].second; + subpolicy.emplace_back(std::move(std::make_pair(operation, prob))); + } + policy_.emplace_back(subpolicy); + } +} + +RandomSelectSubpolicy::RandomSelectSubpolicy( + std::vector, double>>> policy) { + for (int32_t i = 0; i < policy.size(); i++) { + std::vector, double>> subpolicy; + + for (int32_t j = 0; j < policy[i].size(); j++) { + std::shared_ptr op = policy[i][j].first; + std::shared_ptr operation = (op ? op->Parse() : nullptr); + double prob = policy[i][j].second; + subpolicy.emplace_back(std::move(std::make_pair(operation, prob))); + } + policy_.emplace_back(subpolicy); + } +} + RandomSelectSubpolicy::RandomSelectSubpolicy( - std::vector, double>>> policy) - : policy_(policy) {} + std::vector, double>>> policy) { + for (int32_t i = 0; i < policy.size(); i++) { + std::vector, double>> subpolicy; + + for (int32_t j = 0; j < policy[i].size(); j++) { + TensorTransform &op = policy[i][j].first; + std::shared_ptr operation = op.Parse(); + double prob = policy[i][j].second; + subpolicy.emplace_back(std::move(std::make_pair(operation, prob))); + } + policy_.emplace_back(subpolicy); + } +} std::shared_ptr RandomSelectSubpolicy::Parse() { return std::make_shared(policy_); @@ -374,8 +419,8 @@ std::shared_ptr RandomVerticalFlipWithBBox::Parse() { Rescale::Rescale(float rescale, float shift) : rescale_(rescale), shift_(shift) {} std::shared_ptr Rescale::Parse() { return std::make_shared(rescale_, shift_); } +#endif // not ENABLE_ANDROID -#endif // Resize Transform Operation. Resize::Resize(std::vector size, InterpolationMode interpolation) : size_(size), interpolation_(interpolation) {} @@ -389,7 +434,7 @@ std::shared_ptr Resize::Parse(const MapTargetDevice &env) { usize_.reserve(size_.size()); std::transform(size_.begin(), size_.end(), std::back_inserter(usize_), [](int32_t i) { return (uint32_t)i; }); return std::make_shared(usize_); -#endif +#endif // ENABLE_ACL } return std::make_shared(size_, interpolation_); } @@ -399,7 +444,7 @@ std::shared_ptr Resize::Parse(const MapTargetDevice &env) { Rotate::Rotate() {} std::shared_ptr Rotate::Parse() { return std::make_shared(); } -#endif +#endif // ENABLE_ANDROID #ifndef ENABLE_ANDROID // ResizeWithBBox Transform Operation. @@ -442,18 +487,29 @@ SwapRedBlue::SwapRedBlue() {} std::shared_ptr SwapRedBlue::Parse() { return std::make_shared(); } // UniformAug Transform Operation. -UniformAugment::UniformAugment(std::vector> transforms, int32_t num_ops) { - // Convert ops from TensorTransform to TensorOperation +UniformAugment::UniformAugment(const std::vector &transforms, int32_t num_ops) : num_ops_(num_ops) { (void)std::transform( transforms.begin(), transforms.end(), std::back_inserter(transforms_), - [](std::shared_ptr operation) -> std::shared_ptr { return operation->Parse(); }); - num_ops_ = num_ops; + [](TensorTransform *op) -> std::shared_ptr { return op ? op->Parse() : nullptr; }); +} + +UniformAugment::UniformAugment(const std::vector> &transforms, int32_t num_ops) + : num_ops_(num_ops) { + (void)std::transform( + transforms.begin(), transforms.end(), std::back_inserter(transforms_), + [](std::shared_ptr op) -> std::shared_ptr { return op ? op->Parse() : nullptr; }); +} + +UniformAugment::UniformAugment(const std::vector> &transforms, int32_t num_ops) + : num_ops_(num_ops) { + (void)std::transform(transforms.begin(), transforms.end(), std::back_inserter(transforms_), + [](TensorTransform &op) -> std::shared_ptr { return op.Parse(); }); } std::shared_ptr UniformAugment::Parse() { return std::make_shared(transforms_, num_ops_); } -#endif +#endif // not ENABLE_ANDROID } // namespace vision } // namespace dataset diff --git a/mindspore/ccsrc/minddata/dataset/include/vision.h b/mindspore/ccsrc/minddata/dataset/include/vision.h index 2a39b9fda0..c69a996909 100644 --- a/mindspore/ccsrc/minddata/dataset/include/vision.h +++ b/mindspore/ccsrc/minddata/dataset/include/vision.h @@ -61,9 +61,19 @@ class AutoContrast : public TensorTransform { class BoundingBoxAugment : public TensorTransform { public: /// \brief Constructor. - /// \param[in] transform A TensorTransform transform. + /// \param[in] transform Raw pointer to a TensorTransform operation. /// \param[in] ratio Ratio of bounding boxes to apply augmentation on. Range: [0, 1] (default=0.3). - explicit BoundingBoxAugment(std::shared_ptr transform, float ratio = 0.3); + explicit BoundingBoxAugment(TensorTransform *transform, float ratio = 0.3); + + /// \brief Constructor. + /// \param[in] transform Smart pointer to a TensorTransform operation. + /// \param[in] ratio Ratio of bounding boxes to apply augmentation on. Range: [0, 1] (default=0.3). + explicit BoundingBoxAugment(const std::shared_ptr &transform, float ratio = 0.3); + + /// \brief Constructor. + /// \param[in] transform Object pointer to a TensorTransform operation. + /// \param[in] ratio Ratio of bounding boxes to apply augmentation on. Range: [0, 1] (default=0.3). + explicit BoundingBoxAugment(const std::reference_wrapper transform, float ratio = 0.3); /// \brief Destructor. ~BoundingBoxAugment() = default; @@ -620,16 +630,22 @@ class RandomRotation : public TensorTransform { /// \brief RandomSelectSubpolicy TensorTransform. /// \notes Choose a random sub-policy from a list to be applied on the input image. A sub-policy is a list of tuples /// (op, prob), where op is a TensorTransform operation and prob is the probability that this op will be applied. -/// Once a sub-policy is selected, each op within the subpolicy with be applied in sequence according to its +/// Once a sub-policy is selected, each op within the sub-policy with be applied in sequence according to its /// probability. class RandomSelectSubpolicy : public TensorTransform { public: /// \brief Constructor. - /// \param[in] policy Vector of sub-policies to choose from. + /// \param[in] policy Vector of sub-policies to choose from, in which the TensorTransform objects are raw pointers + explicit RandomSelectSubpolicy(std::vector>> policy); - // FIXME - Provide TensorTransform support for policy - explicit RandomSelectSubpolicy(std::vector, double>>> policy); - // RandomSelectSubpolicy(std::vector, double>>> policy); + /// \brief Constructor. + /// \param[in] policy Vector of sub-policies to choose from, in which the TensorTransform objects are shared pointers + explicit RandomSelectSubpolicy(std::vector, double>>> policy); + + /// \brief Constructor. + /// \param[in] policy Vector of sub-policies to choose from, in which the TensorTransform objects are object pointers + explicit RandomSelectSubpolicy( + std::vector, double>>> policy); /// \brief Destructor. ~RandomSelectSubpolicy() = default; @@ -871,9 +887,19 @@ class SwapRedBlue : public TensorTransform { class UniformAugment : public TensorTransform { public: /// \brief Constructor. - /// \param[in] transforms A vector of TensorTransform transforms. + /// \param[in] transforms Raw pointer to vector of TensorTransform operations. + /// \param[in] num_ops An integer representing the number of OPs to be selected and applied. + explicit UniformAugment(const std::vector &transforms, int32_t num_ops = 2); + + /// \brief Constructor. + /// \param[in] transforms Smart pointer to vector of TensorTransform operations. + /// \param[in] num_ops An integer representing the number of OPs to be selected and applied. + explicit UniformAugment(const std::vector> &transforms, int32_t num_ops = 2); + + /// \brief Constructor. + /// \param[in] transforms Object pointer to vector of TensorTransform operations. /// \param[in] num_ops An integer representing the number of OPs to be selected and applied. - explicit UniformAugment(std::vector> transforms, int32_t num_ops = 2); + explicit UniformAugment(const std::vector> &transforms, int32_t num_ops = 2); /// \brief Destructor. ~UniformAugment() = default; diff --git a/mindspore/ccsrc/minddata/dataset/kernels/ir/validators.h b/mindspore/ccsrc/minddata/dataset/kernels/ir/validators.h index 56e058829d..b45e395806 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/ir/validators.h +++ b/mindspore/ccsrc/minddata/dataset/kernels/ir/validators.h @@ -43,12 +43,14 @@ Status ValidateScalar(const std::string &op_name, const std::string &scalar_name const std::vector &range, bool left_open_interval = false, bool right_open_interval = false) { if (range.empty() || range.size() > 2) { std::string err_msg = "Range check expecting size 1 or 2, but got: " + std::to_string(range.size()); + MS_LOG(ERROR) << err_msg; return Status(StatusCode::kMDSyntaxError, __LINE__, __FILE__, err_msg); } if ((left_open_interval && scalar <= range[0]) || (!left_open_interval && scalar < range[0])) { std::string interval_description = left_open_interval ? " greater than " : " greater than or equal to "; std::string err_msg = op_name + ":" + scalar_name + " must be" + interval_description + std::to_string(range[0]) + ", got: " + std::to_string(scalar); + MS_LOG(ERROR) << err_msg; return Status(StatusCode::kMDSyntaxError, __LINE__, __FILE__, err_msg); } if (range.size() == 2) { @@ -58,6 +60,7 @@ Status ValidateScalar(const std::string &op_name, const std::string &scalar_name std::string err_msg = op_name + ":" + scalar_name + " is out of range " + left_bracket + std::to_string(range[0]) + ", " + std::to_string(range[1]) + right_bracket + ", got: " + std::to_string(scalar); + MS_LOG(ERROR) << err_msg; return Status(StatusCode::kMDSyntaxError, __LINE__, __FILE__, err_msg); } } diff --git a/tests/ut/cpp/dataset/CMakeLists.txt b/tests/ut/cpp/dataset/CMakeLists.txt index 4a70adb53d..db2ecc8b2d 100644 --- a/tests/ut/cpp/dataset/CMakeLists.txt +++ b/tests/ut/cpp/dataset/CMakeLists.txt @@ -76,6 +76,7 @@ SET(DE_UT_SRCS ir_callback_test.cc ir_tensor_op_fusion_pass_test.cc ir_tree_adapter_test.cc + ir_vision_test.cc jieba_tokenizer_op_test.cc main_test.cc map_op_test.cc diff --git a/tests/ut/cpp/dataset/c_api_affine_test.cc b/tests/ut/cpp/dataset/c_api_affine_test.cc index ab28c0b205..e8f6147176 100644 --- a/tests/ut/cpp/dataset/c_api_affine_test.cc +++ b/tests/ut/cpp/dataset/c_api_affine_test.cc @@ -31,7 +31,7 @@ TEST_F(MindDataTestPipeline, TestAffineAPI) { // Create an ImageFolder Dataset std::string folder_path = datasets_root_path_ + "/testPK/data/"; - std::shared_ptr ds = ImageFolder(folder_path, true, RandomSampler(false, 5)); + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 5)); // Create a Repeat operation on ds int32_t repeat_num = 3; @@ -74,7 +74,7 @@ TEST_F(MindDataTestPipeline, TestAffineAPIFail) { // Create an ImageFolder Dataset std::string folder_path = datasets_root_path_ + "/testPK/data/"; - std::shared_ptr ds = ImageFolder(folder_path, true, RandomSampler(false, 5)); + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 5)); // Create a Repeat operation on ds int32_t repeat_num = 3; diff --git a/tests/ut/cpp/dataset/c_api_vision_bounding_box_augment_test.cc b/tests/ut/cpp/dataset/c_api_vision_bounding_box_augment_test.cc index 1d4cf58ba0..272d273f1d 100644 --- a/tests/ut/cpp/dataset/c_api_vision_bounding_box_augment_test.cc +++ b/tests/ut/cpp/dataset/c_api_vision_bounding_box_augment_test.cc @@ -26,20 +26,20 @@ class MindDataTestPipeline : public UT::DatasetOpTesting { // Tests for vision C++ API BoundingBoxAugment TensorTransform Operation -TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentSuccess) { - MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentSuccess."; +TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentSuccess1Shr) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentSuccess1Shr."; // Create an VOC Dataset std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; std::shared_ptr ds = VOC(folder_path, "Detection", "train", {}, true, std::make_shared(0, 3)); EXPECT_NE(ds, nullptr); - /* FIXME - Resolve BoundingBoxAugment to properly handle TensorTransform input // Create objects for the tensor ops - std::shared_ptr bound_box_augment = std::make_shared(vision::RandomRotation({90.0}), 1.0); - EXPECT_NE(bound_box_augment, nullptr); + // Use shared pointers + std::shared_ptr random_rotation_op(new vision::RandomRotation({90.0})); + std::shared_ptr bound_box_augment_op(new vision::BoundingBoxAugment({random_rotation_op}, 1.0)); // Create a Map operation on ds - ds = ds->Map({bound_box_augment}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + ds = ds->Map({bound_box_augment_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); EXPECT_NE(ds, nullptr); // Create an iterator over the result of the above dataset @@ -62,22 +62,174 @@ TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentSuccess) { EXPECT_EQ(i, 3); // Manually terminate the pipeline iter->Stop(); - */ } -TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentFail) { - MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentFail with invalid params."; - - // FIXME: For error tests, need to check for failure from CreateIterator execution - /* - // Testing invalid ratio < 0.0 - std::shared_ptr bound_box_augment = std::make_shared(vision::RandomRotation({90.0}), -1.0); - EXPECT_EQ(bound_box_augment, nullptr); - // Testing invalid ratio > 1.0 - std::shared_ptr bound_box_augment1 = std::make_shared(vision::RandomRotation({90.0}), 2.0); - EXPECT_EQ(bound_box_augment1, nullptr); - // Testing invalid transform - std::shared_ptr bound_box_augment2 = std::make_shared(nullptr, 0.5); - EXPECT_EQ(bound_box_augment2, nullptr); - */ +TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentSuccess2Auto) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentSuccess2Auto."; + // Create an VOC Dataset + std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; + std::shared_ptr ds = VOC(folder_path, "Detection", "train", {}, true, std::make_shared(0, 3)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // Use auto for raw pointers + auto random_rotation_op(new vision::RandomRotation({90.0})); + auto bound_box_augment_op(new vision::BoundingBoxAugment({random_rotation_op}, 1.0)); + + // Create a Map operation on ds + ds = ds->Map({bound_box_augment_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + + // Iterate the dataset and get each row + std::unordered_map row; + iter->GetNextRow(&row); + + uint64_t i = 0; + while (row.size() != 0) { + i++; + // auto image = row["image"]; + // MS_LOG(INFO) << "Tensor image shape: " << image->shape(); + iter->GetNextRow(&row); + } + + EXPECT_EQ(i, 3); + // Manually terminate the pipeline + iter->Stop(); +} + +TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentSuccess3Obj) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentSuccess3Obj."; + // Create an VOC Dataset + std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; + std::shared_ptr ds = VOC(folder_path, "Detection", "train", {}, true, std::make_shared(0, 3)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // Use object references + vision::RandomRotation random_rotation_op = vision::RandomRotation({90.0}); + vision::BoundingBoxAugment bound_box_augment_op = vision::BoundingBoxAugment({random_rotation_op}, 1.0); + + // Create a Map operation on ds + ds = ds->Map({bound_box_augment_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + + // Iterate the dataset and get each row + std::unordered_map row; + iter->GetNextRow(&row); + + uint64_t i = 0; + while (row.size() != 0) { + i++; + // auto image = row["image"]; + // MS_LOG(INFO) << "Tensor image shape: " << image->shape(); + iter->GetNextRow(&row); + } + + EXPECT_EQ(i, 3); + // Manually terminate the pipeline + iter->Stop(); +} + +TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentFail1) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentFail1 with invalid ratio parameter."; + + // Create an VOC Dataset + std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; + std::shared_ptr ds = VOC(folder_path, "Detection", "train", {}, true, std::make_shared(0, 3)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + std::shared_ptr random_rotation_op(new vision::RandomRotation({90.0})); + + // Create BoundingBoxAugment op with invalid ratio < 0.0 + std::shared_ptr bound_box_augment_op(new vision::BoundingBoxAugment({random_rotation_op}, -1.0)); + + // Create a Map operation on ds + ds = ds->Map({bound_box_augment_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid BoundingBoxAugment input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentFail2) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentFail2 with invalid ratio parameter."; + + // Create an VOC Dataset + std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; + std::shared_ptr ds = VOC(folder_path, "Detection", "train", {}, true, std::make_shared(0, 3)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + std::shared_ptr random_rotation_op(new vision::RandomRotation({90.0})); + + // Create BoundingBoxAugment op with invalid ratio > 1.0 + std::shared_ptr bound_box_augment_op(new vision::BoundingBoxAugment({random_rotation_op}, 2.0)); + + // Create a Map operation on ds + ds = ds->Map({bound_box_augment_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid BoundingBoxAugment input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentFail3) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentFail3 with invalid transform."; + + // Create an VOC Dataset + std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; + std::shared_ptr ds = VOC(folder_path, "Detection", "train", {}, true, std::make_shared(0, 3)); + EXPECT_NE(ds, nullptr); + + // Create BoundingBoxAugment op with invalid nullptr transform + std::shared_ptr bound_box_augment_op(new vision::BoundingBoxAugment(nullptr, 0.5)); + + // Create a Map operation on ds + ds = ds->Map({bound_box_augment_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid BoundingBoxAugment input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestBoundingBoxAugmentFail4) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestBoundingBoxAugmentFail4 with invalid transform input."; + + // Create an VOC Dataset + std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; + std::shared_ptr ds = VOC(folder_path, "Detection", "train", {}, true, std::make_shared(0, 3)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // RandomRotation has invalid input, first column value of degrees is greater than the second column value + std::shared_ptr random_rotation_op(new vision::RandomRotation({50.0, -50.0})); + + // Create BoundingBoxAugment op with invalid transform + std::shared_ptr bound_box_augment_op(new vision::BoundingBoxAugment({random_rotation_op}, 0.25)); + + // Create a Map operation on ds + ds = ds->Map({bound_box_augment_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid BoundingBoxAugment input + EXPECT_EQ(iter, nullptr); } diff --git a/tests/ut/cpp/dataset/c_api_vision_random_subselect_policy_test.cc b/tests/ut/cpp/dataset/c_api_vision_random_subselect_policy_test.cc index 8c75ea9ac2..c518578dbf 100644 --- a/tests/ut/cpp/dataset/c_api_vision_random_subselect_policy_test.cc +++ b/tests/ut/cpp/dataset/c_api_vision_random_subselect_policy_test.cc @@ -26,23 +26,32 @@ class MindDataTestPipeline : public UT::DatasetOpTesting { // Tests for vision C++ API RandomSelectSubpolicy TensorTransform Operations -TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicySuccess) { - MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicySuccess."; +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicySuccess1Shr) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicySuccess1Shr."; // Create an ImageFolder Dataset std::string folder_path = datasets_root_path_ + "/testPK/data/"; std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); EXPECT_NE(ds, nullptr); - /* FIXME - Resolve RandomSelectSubpolicy to properly handle TensorTransform input // Create objects for the tensor ops + // Use shared pointers // Valid case: TensorTransform is not null and probability is between (0,1) - std::shared_ptr random_select_subpolicy(new vision::RandomSelectSubpolicy( - {{{vision::Invert(), 0.5}, {vision::Equalize(), 0.5}}, {{vision::Resize({15, 15}), 1}}})); - EXPECT_NE(random_select_subpolicy, nullptr); + std::shared_ptr invert_op(new vision::Invert()); + std::shared_ptr equalize_op(new vision::Equalize()); + std::shared_ptr resize_op(new vision::Resize({15, 15})); + + // Prepare input parameters for RandomSelectSubpolicy op + auto invert_pair = std::make_pair(invert_op, 0.5); + auto equalize_pair = std::make_pair(equalize_op, 0.5); + auto resize_pair = std::make_pair(resize_op, 1); + + // Create RandomSelectSubpolicy op + std::vector, double>> policy = {invert_pair, equalize_pair, resize_pair}; + std::shared_ptr random_select_subpolicy_op(new vision::RandomSelectSubpolicy({policy})); // Create a Map operation on ds - ds = ds->Map({random_select_subpolicy}); + ds = ds->Map({random_select_subpolicy_op}); EXPECT_NE(ds, nullptr); // Create an iterator over the result of the above dataset @@ -66,32 +75,281 @@ TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicySuccess) { // Manually terminate the pipeline iter->Stop(); - */ } -TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicyFail) { - MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicyFail."; - // FIXME: For error tests, need to check for failure from CreateIterator execution - /* FIXME - Resolve RandomSelectSubpolicy to properly handle TensorTransform input - // RandomSelectSubpolicy : probability of transform must be between 0.0 and 1.0 - std::shared_ptr random_select_subpolicy1(new vision::RandomSelectSubpolicy( - {{{vision::Invert(), 1.5}, {vision::Equalize(), 0.5}}, {{vision::Resize({15, 15}), 1}}})); - EXPECT_NE(random_select_subpolicy1, nullptr); - - // RandomSelectSubpolicy: policy must not be empty - std::shared_ptr random_select_subpolicy2(new vision::RandomSelectSubpolicy({{{vision::Invert(), 0.5}, {vision::Equalize(), 0.5}}, {{nullptr, 1}}})); - EXPECT_NE(random_select_subpolicy2, nullptr); - - // RandomSelectSubpolicy: policy must not be empty - std::shared_ptr random_select_subpolicy3(new vision::RandomSelectSubpolicy({})); - EXPECT_NE(random_select_subpolicy3, nullptr); - - // RandomSelectSubpolicy: policy must not be empty - std::shared_ptr random_select_subpolicy4(new vision::RandomSelectSubpolicy({{{vision::Invert(), 0.5}, {vision::Equalize(), 0.5}}, {}})); - EXPECT_NE(random_select_subpolicy4, nullptr); - - // RandomSelectSubpolicy: policy must not be empty - std::shared_ptr random_select_subpolicy5(new vision::RandomSelectSubpolicy({{{}, {vision::Equalize(), 0.5}}, {{vision::Resize({15, 15}), 1}}})); - EXPECT_NE(random_select_subpolicy5, nullptr); - */ +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicySuccess2Auto) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicySuccess2Auto."; + + // Create an ImageFolder Dataset + std::string folder_path = datasets_root_path_ + "/testPK/data/"; + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // Use auto for raw pointers + // Valid case: TensorTransform is not null and probability is between (0,1) + auto invert_op(new vision::Invert()); + auto equalize_op(new vision::Equalize()); + auto resize_op(new vision::Resize({15, 15})); + + // Prepare input parameters for RandomSelectSubpolicy op + auto invert_pair = std::make_pair(invert_op, 0.5); + auto equalize_pair = std::make_pair(equalize_op, 0.5); + auto resize_pair = std::make_pair(resize_op, 1); + + std::vector> policy = {invert_pair, equalize_pair, resize_pair}; + + // Create RandomSelectSubpolicy op + auto random_select_subpolicy_op(new vision::RandomSelectSubpolicy({policy})); + + // Create a Map operation on ds + ds = ds->Map({random_select_subpolicy_op}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + + // Iterate the dataset and get each row + std::unordered_map row; + iter->GetNextRow(&row); + + uint64_t i = 0; + while (row.size() != 0) { + i++; + // auto image = row["image"]; + // MS_LOG(INFO) << "Tensor image shape: " << image->shape(); + iter->GetNextRow(&row); + } + + EXPECT_EQ(i, 7); + + // Manually terminate the pipeline + iter->Stop(); +} + +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicySuccess3Obj) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicySuccess3Obj."; + + // Create an ImageFolder Dataset + std::string folder_path = datasets_root_path_ + "/testPK/data/"; + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // Use object references + // Valid case: TensorTransform is not null and probability is between (0,1) + vision::Invert invert_op = vision::Invert(); + vision::Equalize equalize_op = vision::Equalize(); + vision::Resize resize_op = vision::Resize({15, 15}); + + // Prepare input parameters for RandomSelectSubpolicy op + auto invert_pair = std::make_pair(std::ref(invert_op), 0.5); + auto equalize_pair = std::make_pair(std::ref(equalize_op), 0.5); + auto resize_pair = std::make_pair(std::ref(resize_op), 1); + std::vector, double>> policy = {invert_pair, equalize_pair, + resize_pair}; + // Create RandomSelectSubpolicy op + vision::RandomSelectSubpolicy random_select_subpolicy_op = vision::RandomSelectSubpolicy({policy}); + + // Create a Map operation on ds + ds = ds->Map({random_select_subpolicy_op}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + + // Iterate the dataset and get each row + std::unordered_map row; + iter->GetNextRow(&row); + + uint64_t i = 0; + while (row.size() != 0) { + i++; + // auto image = row["image"]; + // MS_LOG(INFO) << "Tensor image shape: " << image->shape(); + iter->GetNextRow(&row); + } + + EXPECT_EQ(i, 7); + + // Manually terminate the pipeline + iter->Stop(); +} + +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicySuccess4MultiPolicy) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicySuccess1MultiPolicy."; + + // Create an ImageFolder Dataset + std::string folder_path = datasets_root_path_ + "/testPK/data/"; + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // Tensor transform ops have shared pointers + // Valid case: TensorTransform is not null and probability is between (0,1) + std::shared_ptr invert_op(new vision::Invert()); + std::shared_ptr equalize_op(new vision::Equalize()); + std::shared_ptr resize_op(new vision::Resize({15, 15})); + + // Prepare input parameters for RandomSelectSubpolicy op + auto invert_pair = std::make_pair(invert_op, 0.75); + auto equalize_pair = std::make_pair(equalize_op, 0.25); + auto resize_pair = std::make_pair(resize_op, 0.5); + + // Create RandomSelectSubpolicy op with 2 policies + std::vector, double>> policy1 = {resize_pair, invert_pair}; + std::vector, double>> policy2 = {equalize_pair}; + std::shared_ptr random_select_subpolicy_op(new vision::RandomSelectSubpolicy({policy1, policy2})); + + // Create a Map operation on ds + ds = ds->Map({random_select_subpolicy_op}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + + // Iterate the dataset and get each row + std::unordered_map row; + iter->GetNextRow(&row); + + uint64_t i = 0; + while (row.size() != 0) { + i++; + // auto image = row["image"]; + // MS_LOG(INFO) << "Tensor image shape: " << image->shape(); + iter->GetNextRow(&row); + } + + EXPECT_EQ(i, 7); + + // Manually terminate the pipeline + iter->Stop(); +} + +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicyFail1) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicyFail1."; + + // Create an ImageFolder Dataset + std::string folder_path = datasets_root_path_ + "/testPK/data/"; + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + std::shared_ptr invert_op(new vision::Invert()); + std::shared_ptr equalize_op(new vision::Equalize()); + std::shared_ptr resize_op(new vision::Resize({15, 15})); + + // Prepare input parameters for RandomSelectSubpolicy op + // For RandomSelectSubpolicy : probability of transform must be between 0.0 and 1.0 + // Equalize pair has invalid negative probability + auto invert_pair = std::make_pair(invert_op, 0.5); + auto equalize_pair = std::make_pair(equalize_op, -0.5); + auto resize_pair = std::make_pair(resize_op, 1); + + // Create RandomSelectSubpolicy op + std::vector, double>> policy = {invert_pair, equalize_pair, resize_pair}; + std::shared_ptr random_select_subpolicy_op(new vision::RandomSelectSubpolicy({policy})); + + // Create a Map operation on ds + ds = ds->Map({random_select_subpolicy_op}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid RandomSelectSubpolicy input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicyFail2) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicyFail2."; + + // Create an ImageFolder Dataset + std::string folder_path = datasets_root_path_ + "/testPK/data/"; + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); + EXPECT_NE(ds, nullptr); + + // Create RandomSelectSubpolicy op with invalid empty subpolicy + std::vector, double>> policy = {}; + std::shared_ptr random_select_subpolicy_op(new vision::RandomSelectSubpolicy({policy})); + + // Create a Map operation on ds + ds = ds->Map({random_select_subpolicy_op}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid RandomSelectSubpolicy input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicyFail3) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicyFail3."; + + // Create an ImageFolder Dataset + std::string folder_path = datasets_root_path_ + "/testPK/data/"; + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + std::shared_ptr invert_op(new vision::Invert()); + std::shared_ptr equalize_op(new vision::Equalize()); + std::shared_ptr resize_op(new vision::Resize({15, 15})); + + // Prepare input parameters for RandomSelectSubpolicy op + auto invert_pair = std::make_pair(invert_op, 0.5); + auto equalize_pair = std::make_pair(equalize_op, 0.5); + auto resize_pair = std::make_pair(resize_op, 1); + + // Prepare pair with nullptr op + auto dummy_pair = std::make_pair(nullptr, 0.25); + + // Create RandomSelectSubpolicy op with invalid nullptr pair + std::vector, double>> policy = {invert_pair, dummy_pair, equalize_pair, + resize_pair}; + std::shared_ptr random_select_subpolicy_op(new vision::RandomSelectSubpolicy({policy})); + + // Create a Map operation on ds + ds = ds->Map({random_select_subpolicy_op}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid RandomSelectSubpolicy input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicyFail4) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSelectSubpolicyFail4."; + + // Create an ImageFolder Dataset + std::string folder_path = datasets_root_path_ + "/testPK/data/"; + std::shared_ptr ds = ImageFolder(folder_path, true, std::make_shared(false, 7)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // Create RandomVerticalFlip op with invalid negative input + std::shared_ptr vertflip_op(new vision::RandomVerticalFlip(-2.0)); + + // Prepare input parameters for RandomSelectSubpolicy op + auto vertflip_pair = std::make_pair(vertflip_op, 1); + + // Create RandomSelectSubpolicy op with invalid transform op within a subpolicy + std::vector, double>> policy = {vertflip_pair}; + std::shared_ptr random_select_subpolicy_op(new vision::RandomSelectSubpolicy({policy})); + + // Create a Map operation on ds + ds = ds->Map({random_select_subpolicy_op}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid RandomSelectSubpolicy input + // EXPECT_EQ(iter, nullptr); + // FIXME - Code bug; this case wrongly succeeds. } diff --git a/tests/ut/cpp/dataset/c_api_vision_uniform_aug_test.cc b/tests/ut/cpp/dataset/c_api_vision_uniform_aug_test.cc index de22c8b681..be08d169c3 100644 --- a/tests/ut/cpp/dataset/c_api_vision_uniform_aug_test.cc +++ b/tests/ut/cpp/dataset/c_api_vision_uniform_aug_test.cc @@ -27,54 +27,55 @@ class MindDataTestPipeline : public UT::DatasetOpTesting { // Tests for vision UniformAugment // Tests for vision C++ API UniformAugment TensorTransform Operations -TEST_F(MindDataTestPipeline, TestUniformAugmentFail1) { - MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail1 with invalid num_ops parameter."; - // FIXME: For error tests, need to check for failure from CreateIterator execution - /* - // Create objects for the tensor ops - std::shared_ptr random_crop_op(new vision::RandomCrop({28, 28})); - EXPECT_NE(random_crop_op, nullptr); +TEST_F(MindDataTestPipeline, TestUniformAugWithOps1Shr) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugWithOps1Shr."; - std::shared_ptr center_crop_op(new vision::CenterCrop({16, 16})); - EXPECT_NE(center_crop_op, nullptr); + // Create a Mnist Dataset + std::string folder_path = datasets_root_path_ + "/testMnistData/"; + std::shared_ptr ds = Mnist(folder_path, "all", std::make_shared(false, 20)); + EXPECT_NE(ds, nullptr); - // FIXME: For error tests, need to check for failure from CreateIterator execution - // UniformAug: num_ops must be greater than 0 - std::shared_ptr uniform_aug_op1(new vision::UniformAugment({random_crop_op, center_crop_op}, 0)); - EXPECT_EQ(uniform_aug_op1, nullptr); + // Create a Repeat operation on ds + int32_t repeat_num = 1; + ds = ds->Repeat(repeat_num); + EXPECT_NE(ds, nullptr); - // UniformAug: num_ops must be greater than 0 - std::shared_ptr uniform_aug_op2(new vision::UniformAugment({random_crop_op, center_crop_op}, -1)); - EXPECT_EQ(uniform_aug_op2, nullptr); + // Create objects for the tensor ops + // Use shared pointers + std::shared_ptr resize_op(new vision::Resize({30, 30})); + std::shared_ptr random_crop_op(new vision::RandomCrop({28, 28})); + std::shared_ptr center_crop_op(new vision::CenterCrop({16, 16})); + std::shared_ptr uniform_aug_op(new vision::UniformAugment({random_crop_op, center_crop_op}, 2)); - // UniformAug: num_ops is greater than transforms size - std::shared_ptr uniform_aug_op3(new vision::UniformAugment({random_crop_op, center_crop_op}, 3)); - EXPECT_EQ(uniform_aug_op3, nullptr); - */ + // Create a Map operation on ds + ds = ds->Map({resize_op, uniform_aug_op}); + EXPECT_NE(ds, nullptr); -} + // Create an iterator over the result of the above dataset + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); -TEST_F(MindDataTestPipeline, TestUniformAugmentFail2) { - MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail2 with invalid transform."; + // Iterate the dataset and get each row + std::unordered_map row; + iter->GetNextRow(&row); - // FIXME: For error tests, need to check for failure from CreateIterator execution - /* - // UniformAug: transform ops must not be null - std::shared_ptr uniform_aug_op1(new vision::UniformAugment({vision::RandomCrop({-28})}, 1)); - EXPECT_NE(uniform_aug_op1, nullptr); + uint64_t i = 0; + while (row.size() != 0) { + i++; + // auto image = row["image"]; + // MS_LOG(INFO) << "Tensor image shape: " << image->shape(); + iter->GetNextRow(&row); + } - // UniformAug: transform ops must not be null - std::shared_ptr uniform_aug_op2(new vision::UniformAugment({vision::RandomCrop({28}), nullptr}, 2)); - EXPECT_NE(uniform_aug_op2, nullptr); + EXPECT_EQ(i, 20); - // UniformAug: transform list must not be empty - std::shared_ptr uniform_aug_op3(new vision::UniformAugment({}, 1)); - EXPECT_NE(uniform_aug_op3, nullptr); - */ + // Manually terminate the pipeline + iter->Stop(); } -TEST_F(MindDataTestPipeline, TestUniformAugWithOps) { - MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugWithOps."; +TEST_F(MindDataTestPipeline, TestUniformAugWithOps2Auto) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugWithOps2Auto."; // Create a Mnist Dataset std::string folder_path = datasets_root_path_ + "/testMnistData/"; @@ -87,17 +88,58 @@ TEST_F(MindDataTestPipeline, TestUniformAugWithOps) { EXPECT_NE(ds, nullptr); // Create objects for the tensor ops - std::shared_ptr resize_op(new vision::Resize({30, 30})); - EXPECT_NE(resize_op, nullptr); + // Use auto for raw pointers + auto resize_op(new vision::Resize({30, 30})); + auto random_crop_op(new vision::RandomCrop({28, 28})); + auto center_crop_op(new vision::CenterCrop({16, 16})); + auto uniform_aug_op(new vision::UniformAugment({random_crop_op, center_crop_op}, 2)); - std::shared_ptr random_crop_op(new vision::RandomCrop({28, 28})); - EXPECT_NE(random_crop_op, nullptr); + // Create a Map operation on ds + ds = ds->Map({resize_op, uniform_aug_op}); + EXPECT_NE(ds, nullptr); - std::shared_ptr center_crop_op(new vision::CenterCrop({16, 16})); - EXPECT_NE(center_crop_op, nullptr); + // Create an iterator over the result of the above dataset + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); - std::shared_ptr uniform_aug_op(new vision::UniformAugment({random_crop_op, center_crop_op}, 2)); - EXPECT_NE(uniform_aug_op, nullptr); + // Iterate the dataset and get each row + std::unordered_map row; + iter->GetNextRow(&row); + + uint64_t i = 0; + while (row.size() != 0) { + i++; + // auto image = row["image"]; + // MS_LOG(INFO) << "Tensor image shape: " << image->shape(); + iter->GetNextRow(&row); + } + + EXPECT_EQ(i, 20); + + // Manually terminate the pipeline + iter->Stop(); +} + +TEST_F(MindDataTestPipeline, TestUniformAugWithOps3Obj) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugWithOps3Obj."; + + // Create a Mnist Dataset + std::string folder_path = datasets_root_path_ + "/testMnistData/"; + std::shared_ptr ds = Mnist(folder_path, "all", std::make_shared(false, 20)); + EXPECT_NE(ds, nullptr); + + // Create a Repeat operation on ds + int32_t repeat_num = 1; + ds = ds->Repeat(repeat_num); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // Use object references + vision::Resize resize_op = vision::Resize({30, 30}); + vision::RandomCrop random_crop_op = vision::RandomCrop({28, 28}); + vision::CenterCrop center_crop_op = vision::CenterCrop({16, 16}); + vision::UniformAugment uniform_aug_op = vision::UniformAugment({random_crop_op, center_crop_op}, 2); // Create a Map operation on ds ds = ds->Map({resize_op, uniform_aug_op}); @@ -125,3 +167,124 @@ TEST_F(MindDataTestPipeline, TestUniformAugWithOps) { // Manually terminate the pipeline iter->Stop(); } + +TEST_F(MindDataTestPipeline, TestUniformAugmentFail1num_ops) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail1num_ops with invalid num_ops parameter."; + + // Create a Mnist Dataset + std::string folder_path = datasets_root_path_ + "/testMnistData/"; + std::shared_ptr ds = Mnist(folder_path, "all", std::make_shared(false, 20)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + std::shared_ptr random_crop_op(new vision::RandomCrop({28, 28})); + std::shared_ptr center_crop_op(new vision::CenterCrop({16, 16})); + + // UniformAug: num_ops must be greater than 0 + std::shared_ptr uniform_aug_op(new vision::UniformAugment({random_crop_op, center_crop_op}, 0)); + + // Create a Map operation on ds + ds = ds->Map({uniform_aug_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid UniformAugment input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestUniformAugmentFail2num_ops) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail2num_ops with invalid num_ops parameter."; + + // Create a Mnist Dataset + std::string folder_path = datasets_root_path_ + "/testMnistData/"; + std::shared_ptr ds = Mnist(folder_path, "all", std::make_shared(false, 20)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + std::shared_ptr random_crop_op(new vision::RandomCrop({28, 28})); + std::shared_ptr center_crop_op(new vision::CenterCrop({16, 16})); + + // UniformAug: num_ops is greater than transforms size + std::shared_ptr uniform_aug_op(new vision::UniformAugment({random_crop_op, center_crop_op}, 3)); + + // Create a Map operation on ds + ds = ds->Map({uniform_aug_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid UniformAugment input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestUniformAugmentFail3transforms) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail3transforms with invalid transform."; + + // Create a Mnist Dataset + std::string folder_path = datasets_root_path_ + "/testMnistData/"; + std::shared_ptr ds = Mnist(folder_path, "all", std::make_shared(false, 20)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + // RandomRotation has invalid input, negative size + std::shared_ptr random_crop_op(new vision::RandomCrop({-28})); + + // Create UniformAug op with invalid transform op + std::shared_ptr uniform_aug_op(new vision::UniformAugment({random_crop_op}, 1)); + + // Create a Map operation on ds + ds = ds->Map({uniform_aug_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid UniformAugment input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestUniformAugmentFail4transforms) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail4transforms with invalid transform."; + + // Create a Mnist Dataset + std::string folder_path = datasets_root_path_ + "/testMnistData/"; + std::shared_ptr ds = Mnist(folder_path, "all", std::make_shared(false, 20)); + EXPECT_NE(ds, nullptr); + + // Create objects for the tensor ops + std::shared_ptr random_crop_op(new vision::RandomCrop({28})); + + // Create UniformAug op with invalid transform op, nullptr + std::shared_ptr uniform_aug_op(new vision::UniformAugment({random_crop_op, nullptr}, 2)); + + // Create a Map operation on ds + ds = ds->Map({uniform_aug_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid UniformAugment input + EXPECT_EQ(iter, nullptr); +} + +TEST_F(MindDataTestPipeline, TestUniformAugmentFail5transforms) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail5transforms with invalid transform."; + + // Create a Mnist Dataset + std::string folder_path = datasets_root_path_ + "/testMnistData/"; + std::shared_ptr ds = Mnist(folder_path, "all", std::make_shared(false, 20)); + EXPECT_NE(ds, nullptr); + + // Create UniformAug op with invalid transform op empty list + std::vector> list = {}; + std::shared_ptr uniform_aug_op(new vision::UniformAugment(list, 1)); + + // Create a Map operation on ds + ds = ds->Map({uniform_aug_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"}); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: Invalid UniformAugment input + EXPECT_EQ(iter, nullptr); +} diff --git a/tests/ut/cpp/dataset/common/common.h b/tests/ut/cpp/dataset/common/common.h index f9dcb0abed..474a2c41ee 100644 --- a/tests/ut/cpp/dataset/common/common.h +++ b/tests/ut/cpp/dataset/common/common.h @@ -41,6 +41,24 @@ using mindspore::StatusCode; } \ } while (false) +#define ASSERT_ERROR(_s) \ + do { \ + Status __rc = (_s); \ + if (__rc.IsOk()) { \ + MS_LOG(ERROR) << __rc.ToString() << "."; \ + ASSERT_TRUE(false); \ + } \ + } while (false) + +#define EXPECT_ERROR(_s) \ + do { \ + Status __rc = (_s); \ + if (__rc.IsOk()) { \ + MS_LOG(ERROR) << __rc.ToString() << "."; \ + EXPECT_TRUE(false); \ + } \ + } while (false) + namespace UT { class Common : public testing::Test { public: diff --git a/tests/ut/cpp/dataset/ir_vision_test.cc b/tests/ut/cpp/dataset/ir_vision_test.cc new file mode 100644 index 0000000000..5e07eb38a0 --- /dev/null +++ b/tests/ut/cpp/dataset/ir_vision_test.cc @@ -0,0 +1,95 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "common/common.h" +#include "minddata/dataset/include/datasets.h" +#include "minddata/dataset/include/transforms.h" +#include "minddata/dataset/include/vision.h" +#include "minddata/dataset/kernels/ir/vision/vision_ir.h" + +using namespace mindspore::dataset; + +class MindDataTestIRVision : public UT::DatasetOpTesting { + public: + MindDataTestIRVision() = default; +}; + + +TEST_F(MindDataTestIRVision, TestAutoContrastIRFail1) { + MS_LOG(INFO) << "Doing MindDataTestIRVision-TestAutoContrastIRFail1."; + + // Testing invalid cutoff < 0 + std::shared_ptr auto_contrast1(new vision::AutoContrastOperation(-1.0,{})); + ASSERT_NE(auto_contrast1, nullptr); + + Status rc1 = auto_contrast1->ValidateParams(); + EXPECT_ERROR(rc1); + + // Testing invalid cutoff > 100 + std::shared_ptr auto_contrast2(new vision::AutoContrastOperation(110.0, {10, 20})); + ASSERT_NE(auto_contrast2, nullptr); + + Status rc2 = auto_contrast2->ValidateParams(); + EXPECT_ERROR(rc2); +} + +TEST_F(MindDataTestIRVision, TestNormalizeFail) { + MS_LOG(INFO) << "Doing MindDataTestIRVision-TestNormalizeFail with invalid parameters."; + + // std value at 0.0 + std::shared_ptr normalize1(new vision::NormalizeOperation({121.0, 115.0, 100.0}, {0.0, 68.0, 71.0})); + ASSERT_NE(normalize1, nullptr); + + Status rc1 = normalize1->ValidateParams(); + EXPECT_ERROR(rc1); + + // mean out of range + std::shared_ptr normalize2(new vision::NormalizeOperation({121.0, 0.0, 100.0}, {256.0, 68.0, 71.0})); + ASSERT_NE(normalize2, nullptr); + + Status rc2 = normalize2->ValidateParams(); + EXPECT_ERROR(rc2); + + // mean out of range + std::shared_ptr normalize3(new vision::NormalizeOperation({256.0, 0.0, 100.0}, {70.0, 68.0, 71.0})); + ASSERT_NE(normalize3, nullptr); + + Status rc3 = normalize3->ValidateParams(); + EXPECT_ERROR(rc3); + + // mean out of range + std::shared_ptr normalize4(new vision::NormalizeOperation({-1.0, 0.0, 100.0}, {70.0, 68.0, 71.0})); + ASSERT_NE(normalize4, nullptr); + + Status rc4 = normalize4->ValidateParams(); + EXPECT_ERROR(rc4); + + // normalize with 2 values (not 3 values) for mean + std::shared_ptr normalize5(new vision::NormalizeOperation({121.0, 115.0}, {70.0, 68.0, 71.0})); + ASSERT_NE(normalize5, nullptr); + + Status rc5 = normalize5->ValidateParams(); + EXPECT_ERROR(rc5); + + // normalize with 2 values (not 3 values) for standard deviation + std::shared_ptr normalize6(new vision::NormalizeOperation({121.0, 115.0, 100.0}, {68.0, 71.0})); + ASSERT_NE(normalize6, nullptr); + + Status rc6 = normalize6->ValidateParams(); + EXPECT_ERROR(rc6); +}