Browse Source

C++ api add TypeCaseOp & RandomCropDecodeResizeOp

tags/v1.1.0
YangLuo 5 years ago
parent
commit
9e033bbe19
6 changed files with 335 additions and 0 deletions
  1. +29
    -0
      mindspore/ccsrc/minddata/dataset/api/transforms.cc
  2. +75
    -0
      mindspore/ccsrc/minddata/dataset/api/vision.cc
  3. +22
    -0
      mindspore/ccsrc/minddata/dataset/include/transforms.h
  4. +37
    -0
      mindspore/ccsrc/minddata/dataset/include/vision.h
  5. +58
    -0
      tests/ut/cpp/dataset/c_api_transforms_test.cc
  6. +114
    -0
      tests/ut/cpp/dataset/c_api_vision_test.cc

+ 29
- 0
mindspore/ccsrc/minddata/dataset/api/transforms.cc View File

@@ -19,6 +19,7 @@

// Kernel data headers (in alphabetical order)
#include "minddata/dataset/kernels/data/one_hot_op.h"
#include "minddata/dataset/kernels/data/type_cast_op.h"

namespace mindspore {
namespace dataset {
@@ -42,6 +43,16 @@ std::shared_ptr<OneHotOperation> OneHot(int32_t num_classes) {
return op;
}

// Function to create TypeCastOperation.
std::shared_ptr<TypeCastOperation> TypeCast(std::string data_type) {
auto op = std::make_shared<TypeCastOperation>(data_type);
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}

/* ####################################### Validator Functions ############################################ */

/* ####################################### Derived TensorOperation classes ################################# */
@@ -62,6 +73,24 @@ bool OneHotOperation::ValidateParams() {

std::shared_ptr<TensorOp> OneHotOperation::Build() { return std::make_shared<OneHotOp>(num_classes_); }

// TypeCastOperation
TypeCastOperation::TypeCastOperation(std::string data_type) : data_type_(data_type) {}

bool TypeCastOperation::ValidateParams() {
std::vector<std::string> predefine_type = {"bool", "int8", "uint8", "int16", "uint16", "int32", "uint32",
"int64", "uint64", "float16", "float32", "float64", "string"};
auto itr = std::find(predefine_type.begin(), predefine_type.end(), data_type_);
if (itr == predefine_type.end()) {
MS_LOG(ERROR) << "TypeCast: Only support type bool, int8, uint8, int16, uint16, int32, uint32, "
<< "int64, uint64, float16, float32, float64, string, but got " << data_type_;
return false;
}

return true;
}

std::shared_ptr<TensorOp> TypeCastOperation::Build() { return std::make_shared<TypeCastOp>(data_type_); }

} // namespace transforms
} // namespace api
} // namespace dataset


+ 75
- 0
mindspore/ccsrc/minddata/dataset/api/vision.cc View File

@@ -32,6 +32,7 @@
#include "minddata/dataset/kernels/image/random_color_op.h"
#include "minddata/dataset/kernels/image/random_color_adjust_op.h"
#include "minddata/dataset/kernels/image/random_crop_op.h"
#include "minddata/dataset/kernels/image/random_crop_decode_resize_op.h"
#include "minddata/dataset/kernels/image/random_horizontal_flip_op.h"
#include "minddata/dataset/kernels/image/random_posterize_op.h"
#include "minddata/dataset/kernels/image/random_rotation_op.h"
@@ -200,6 +201,20 @@ std::shared_ptr<RandomCropOperation> RandomCrop(std::vector<int32_t> size, std::
return op;
}

// Function to create RandomCropDecodeResizeOperation.
std::shared_ptr<RandomCropDecodeResizeOperation> RandomCropDecodeResize(std::vector<int32_t> size,
std::vector<float> scale,
std::vector<float> ratio,
InterpolationMode interpolation,
int32_t max_attempts) {
auto op = std::make_shared<RandomCropDecodeResizeOperation>(size, scale, ratio, interpolation, max_attempts);
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}

// Function to create RandomHorizontalFlipOperation.
std::shared_ptr<RandomHorizontalFlipOperation> RandomHorizontalFlip(float prob) {
auto op = std::make_shared<RandomHorizontalFlipOperation>(prob);
@@ -784,6 +799,66 @@ std::shared_ptr<TensorOp> RandomCropOperation::Build() {
return tensor_op;
}

// RandomCropDecodeResizeOperation
RandomCropDecodeResizeOperation::RandomCropDecodeResizeOperation(std::vector<int32_t> size, std::vector<float> scale,
std::vector<float> ratio,
InterpolationMode interpolation, int32_t max_attempts)
: size_(size), scale_(scale), ratio_(ratio), interpolation_(interpolation), max_attempts_(max_attempts) {}

bool RandomCropDecodeResizeOperation::ValidateParams() {
if (size_.empty() || size_.size() > 2) {
MS_LOG(ERROR) << "RandomCropDecodeResize: size vector has incorrect size: " << size_.size();
return false;
}

if (scale_.empty() || scale_.size() != 2) {
MS_LOG(ERROR) << "RandomCropDecodeResize: scale vector has incorrect size: " << scale_.size();
return false;
}

if (scale_[0] > scale_[1]) {
MS_LOG(ERROR) << "RandomCropDecodeResize: scale should be in (min,max) format. Got (max,min).";
return false;
}

if (ratio_.empty() || ratio_.size() != 2) {
MS_LOG(ERROR) << "RandomCropDecodeResize: ratio vector has incorrect size: " << ratio_.size();
return false;
}

if (ratio_[0] > ratio_[1]) {
MS_LOG(ERROR) << "RandomCropDecodeResize: ratio should be in (min,max) format. Got (max,min).";
return false;
}

if (max_attempts_ < 1) {
MS_LOG(ERROR) << "RandomCropDecodeResize: max_attempts must be greater than or equal to 1.";
return false;
}
return true;
}

std::shared_ptr<TensorOp> RandomCropDecodeResizeOperation::Build() {
int32_t crop_height = size_[0];
int32_t crop_width = size_[0];

// User has specified the crop_width value.
if (size_.size() == 2) {
crop_width = size_[1];
}

float scale_lower_bound = scale_[0];
float scale_upper_bound = scale_[1];

float aspect_lower_bound = ratio_[0];
float aspect_upper_bound = ratio_[1];

auto tensor_op =
std::make_shared<RandomCropDecodeResizeOp>(crop_height, crop_width, scale_lower_bound, scale_upper_bound,
aspect_lower_bound, aspect_upper_bound, interpolation_, max_attempts_);
return tensor_op;
}

// RandomHorizontalFlipOperation
RandomHorizontalFlipOperation::RandomHorizontalFlipOperation(float probability) : probability_(probability) {}



+ 22
- 0
mindspore/ccsrc/minddata/dataset/include/transforms.h View File

@@ -19,6 +19,7 @@

#include <vector>
#include <memory>
#include <string>
#include "minddata/dataset/core/constants.h"

namespace mindspore {
@@ -48,6 +49,7 @@ namespace transforms {

// Transform Op classes (in alphabetical order)
class OneHotOperation;
class TypeCastOperation;

/// \brief Function to create a OneHot TensorOperation.
/// \notes Convert the labels into OneHot format.
@@ -55,6 +57,12 @@ class OneHotOperation;
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<OneHotOperation> OneHot(int32_t num_classes);

/// \brief Function to create a TypeCast TensorOperation.
/// \notes Tensor operation to cast to a given MindSpore data type.
/// \param[in] data_type mindspore.dtype to be cast to.
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<TypeCastOperation> TypeCast(std::string data_type);

/* ####################################### Derived TensorOperation classes ################################# */

class OneHotOperation : public TensorOperation {
@@ -70,6 +78,20 @@ class OneHotOperation : public TensorOperation {
private:
float num_classes_;
};

class TypeCastOperation : public TensorOperation {
public:
explicit TypeCastOperation(std::string data_type);

~TypeCastOperation() = default;

std::shared_ptr<TensorOp> Build() override;

bool ValidateParams() override;

private:
std::string data_type_;
};
} // namespace transforms
} // namespace api
} // namespace dataset


+ 37
- 0
mindspore/ccsrc/minddata/dataset/include/vision.h View File

@@ -43,6 +43,7 @@ class RandomAffineOperation;
class RandomColorOperation;
class RandomColorAdjustOperation;
class RandomCropOperation;
class RandomCropDecodeResizeOperation;
class RandomHorizontalFlipOperation;
class RandomPosterizeOperation;
class RandomRotationOperation;
@@ -196,6 +197,23 @@ std::shared_ptr<RandomCropOperation> RandomCrop(std::vector<int32_t> size, std::
bool pad_if_needed = false, std::vector<uint8_t> fill_value = {0, 0, 0},
BorderType padding_mode = BorderType::kConstant);

/// \brief Function to create a RandomCropDecodeResize TensorOperation.
/// \notes Equivalent to RandomResizedCrop, but crops before decodes.
/// \param[in] size - a vector representing the output size of the cropped image.
/// If size is a single value, a square crop of size (size, size) is returned.
/// If size has 2 values, it should be (height, width).
/// \param[in] scale - range [min, max) of respective size of the
/// original size to be cropped (default=(0.08, 1.0))
/// \param[in] ratio - range [min, max) of aspect ratio to be
/// cropped (default=(3. / 4., 4. / 3.))
/// \param[in] interpolation - an enum for the mode of interpolation
/// \param[in] The maximum number of attempts to propose a valid crop_area (default=10).
/// If exceeded, fall back to use center_crop instead.
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<RandomCropDecodeResizeOperation> RandomCropDecodeResize(
std::vector<int32_t> size, std::vector<float> scale = {0.08, 1.0}, std::vector<float> ratio = {3. / 4, 4. / 3},
InterpolationMode interpolation = InterpolationMode::kLinear, int32_t max_attempts = 10);

/// \brief Function to create a RandomHorizontalFlip TensorOperation.
/// \notes Tensor operation to perform random horizontal flip.
/// \param[in] prob - float representing the probability of flip.
@@ -480,6 +498,25 @@ class RandomCropOperation : public TensorOperation {
BorderType padding_mode_;
};

class RandomCropDecodeResizeOperation : public TensorOperation {
public:
RandomCropDecodeResizeOperation(std::vector<int32_t> size, std::vector<float> scale, std::vector<float> ratio,
InterpolationMode interpolation, int32_t max_attempts);

~RandomCropDecodeResizeOperation() = default;

std::shared_ptr<TensorOp> Build() override;

bool ValidateParams() override;

private:
std::vector<int32_t> size_;
std::vector<float> scale_;
std::vector<float> ratio_;
InterpolationMode interpolation_;
int32_t max_attempts_;
};

class RandomHorizontalFlipOperation : public TensorOperation {
public:
explicit RandomHorizontalFlipOperation(float probability = 0.5);


+ 58
- 0
tests/ut/cpp/dataset/c_api_transforms_test.cc View File

@@ -142,3 +142,61 @@ TEST_F(MindDataTestPipeline, TestOneHotSuccess2) {
// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestTypeCastSuccess) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestTypeCastSuccess.";

// Create a Cifar10 Dataset
std::string folder_path = datasets_root_path_ + "/testCifar10Data/";
std::shared_ptr<Dataset> ds = Cifar10(folder_path, "all", RandomSampler(false, 1));
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<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

// Check original data type of dataset
auto image = row["image"];
std::string ori_type = image->type().ToString();
MS_LOG(INFO) << "Original data type: " << ori_type;
EXPECT_NE(ori_type.c_str(), "uint8");

// Manually terminate the pipeline
iter->Stop();

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> type_cast = transforms::TypeCast("uint16");
EXPECT_NE(type_cast, nullptr);

// Create a Map operation on ds
std::shared_ptr<Dataset> ds2 = ds->Map({type_cast}, {"image"});
EXPECT_NE(ds2, 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<Iterator> iter2 = ds2->CreateIterator();
EXPECT_NE(iter2, nullptr);

// Check current data type of dataset
iter2->GetNextRow(&row);
auto image2 = row["image"];
std::string cur_type = image2->type().ToString();
MS_LOG(INFO) << "Current data type: " << cur_type;
EXPECT_NE(cur_type.c_str(), "uint16");

// Manually terminate the pipeline
iter2->Stop();
}

TEST_F(MindDataTestPipeline, TestTypeCastFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestTypeCastFail with invalid params.";

// incorrect data type
std::shared_ptr<TensorOperation> type_cast = transforms::TypeCast("char");
EXPECT_EQ(type_cast, nullptr);
}

+ 114
- 0
tests/ut/cpp/dataset/c_api_vision_test.cc View File

@@ -1313,3 +1313,117 @@ TEST_F(MindDataTestPipeline, TestNormalizeFail) {
normalize = mindspore::dataset::api::vision::Normalize({300.0, 115.0, 100.0}, {70.0, 68.0, 71.0});
EXPECT_EQ(normalize, nullptr);
}

TEST_F(MindDataTestPipeline, TestRandomCropDecodeResizeSucess1) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomCropDecodeResize with default params.";
// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, false, SequentialSampler(0, 2));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> random_crop_decode_resize =
mindspore::dataset::api::vision::RandomCropDecodeResize({50, 60});
EXPECT_NE(random_crop_decode_resize, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_crop_decode_resize});
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<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> 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(image->shape()[0], 50);
EXPECT_EQ(image->shape()[1], 60);
}

EXPECT_EQ(i, 2);

// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomCropDecodeResizeSucess2) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomCropDecodeResize with single size.";
// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, false, RandomSampler(false, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> random_crop_decode_resize =
mindspore::dataset::api::vision::RandomCropDecodeResize({100});
EXPECT_NE(random_crop_decode_resize, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_crop_decode_resize});
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<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> 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(image->shape()[0], 100);
EXPECT_EQ(image->shape()[1], 100);
}

EXPECT_EQ(i, 3);

// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomCropDecodeResizeFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomCropDecodeResize with invalid params.";
// size of size vector is not 1 or 2
std::shared_ptr<TensorOperation> random_crop_decode_resize_1 =
mindspore::dataset::api::vision::RandomCropDecodeResize({50, 100, 150});
EXPECT_EQ(random_crop_decode_resize_1, nullptr);

// incorrect scale vector
std::shared_ptr<TensorOperation> random_crop_decode_resize_2 =
mindspore::dataset::api::vision::RandomCropDecodeResize({50, 50}, {0.5});
EXPECT_EQ(random_crop_decode_resize_2, nullptr);

std::shared_ptr<TensorOperation> random_crop_decode_resize_3 =
mindspore::dataset::api::vision::RandomCropDecodeResize({50, 50}, {0.5, 0.1});
EXPECT_EQ(random_crop_decode_resize_3, nullptr);

// incorrect ratio vector
std::shared_ptr<TensorOperation> random_crop_decode_resize_4 =
mindspore::dataset::api::vision::RandomCropDecodeResize({50, 50}, {0.5, 0.6}, {0.9});
EXPECT_EQ(random_crop_decode_resize_4, nullptr);

std::shared_ptr<TensorOperation> random_crop_decode_resize_5 =
mindspore::dataset::api::vision::RandomCropDecodeResize({50, 50}, {0.5, 0.6}, {0.9, 0.1});
EXPECT_EQ(random_crop_decode_resize_5, nullptr);

// incorrect max_attempts range
std::shared_ptr<TensorOperation> random_crop_decode_resize_6 =
mindspore::dataset::api::vision::RandomCropDecodeResize({50, 50}, {0.5, 0.6}, {0.9, 0.9},
mindspore::dataset::InterpolationMode::kLinear, 0);
EXPECT_EQ(random_crop_decode_resize_6, nullptr);
}

Loading…
Cancel
Save