C++ api add TypeCaseOp & RandomCropDecodeResizeOp

This commit is contained in:
YangLuo 2020-10-12 14:38:48 +08:00
parent 512a3e33b8
commit 9e033bbe19
6 changed files with 335 additions and 0 deletions

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

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) {}

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

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);

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);
}

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);
}