add dtype validation for RandomCropWithBbox
This commit is contained in:
parent
67c6d9733e
commit
f180e1f9d2
|
@ -92,19 +92,22 @@ Tensor &Tensor::operator=(Tensor &&other) noexcept {
|
|||
}
|
||||
|
||||
Status Tensor::CreateEmpty(const TensorShape &shape, const DataType &type, TensorPtr *out) {
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(shape.known(), "Invalid shape.");
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(type != DataType::DE_UNKNOWN, "Invalid data type.");
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(shape.known(), "Failed to create empty tensor, tensor shape is unknown.");
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(type != DataType::DE_UNKNOWN, "Failed to create empty tensor, data type is unknown.");
|
||||
RETURN_UNEXPECTED_IF_NULL(out);
|
||||
const TensorAlloc *alloc = GlobalContext::Instance()->tensor_allocator();
|
||||
*out = std::allocate_shared<Tensor>(*alloc, shape, type);
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(out != nullptr, "Allocate memory failed.");
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(out != nullptr, "Failed to create empty tensor, allocate memory failed.");
|
||||
// if it's a string tensor and it has no elements, Just initialize the shape and type.
|
||||
if (!type.IsNumeric() && shape.NumOfElements() == 0) {
|
||||
return Status::OK();
|
||||
if (!type.IsNumeric()) {
|
||||
if (shape.NumOfElements() == 0) {
|
||||
return Status::OK();
|
||||
} else {
|
||||
RETURN_STATUS_UNEXPECTED(
|
||||
"Failed to create empty tensor, number of elements should be 0 when data type is string.");
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(type.IsNumeric(), "Number of elements is not 0. The type should be numeric.");
|
||||
|
||||
int64_t byte_size = (*out)->SizeInBytes();
|
||||
|
||||
// Don't allocate if we have a tensor with no elements.
|
||||
|
@ -197,7 +200,11 @@ Status Tensor::CreateFromNpString(py::array arr, std::shared_ptr<Tensor> *out) {
|
|||
|
||||
Status Tensor::CreateFromNpArray(const py::array &arr, std::shared_ptr<Tensor> *out) {
|
||||
RETURN_UNEXPECTED_IF_NULL(out);
|
||||
if (DataType::FromNpArray(arr) == DataType::DE_STRING) {
|
||||
DataType type = DataType::FromNpArray(arr);
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(type != DataType::DE_UNKNOWN,
|
||||
"Failed to create tensor from numpy array, data type is unknown.");
|
||||
|
||||
if (type == DataType::DE_STRING) {
|
||||
return CreateFromNpString(arr, out);
|
||||
}
|
||||
|
||||
|
@ -221,10 +228,10 @@ Status Tensor::CreateFromNpArray(const py::array &arr, std::shared_ptr<Tensor> *
|
|||
unsigned char *data = static_cast<unsigned char *>(arr.request().ptr);
|
||||
|
||||
if (is_strided) {
|
||||
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape(shape), DataType::FromNpArray(arr), out));
|
||||
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape(shape), type, out));
|
||||
RETURN_IF_NOT_OK(CopyStridedArray((*out)->data_, data, shape, strides, (*out)->type_.SizeInBytes()));
|
||||
} else {
|
||||
RETURN_IF_NOT_OK(Tensor::CreateFromMemory(TensorShape(shape), DataType::FromNpArray(arr), data, out));
|
||||
RETURN_IF_NOT_OK(Tensor::CreateFromMemory(TensorShape(shape), type, data, out));
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
|
|
@ -142,7 +142,17 @@ Status ValidateImage(const std::shared_ptr<Tensor> &image, const std::string &op
|
|||
if (valid_rank.find(rank) == valid_rank.end()) {
|
||||
std::string err_msg = op_name + ": the dimension of image tensor does not match the requirement of operator.";
|
||||
err_msg += " Expecting tensor in dimension of " + NumberSetToString(valid_rank);
|
||||
if (valid_rank == std::set<dsize_t>({kMinImageRank, kDefaultImageRank})) {
|
||||
err_msg += ", in shape of <H, W> or <H, W, C>";
|
||||
} else if (valid_rank == std::set<dsize_t>({kMinImageRank})) {
|
||||
err_msg += ", in shape of <H, W>";
|
||||
} else if (valid_rank == std::set<dsize_t>({kDefaultImageRank})) {
|
||||
err_msg += ", in shape of <H, W, C>";
|
||||
}
|
||||
err_msg += ". But got dimension " + std::to_string(rank) + ".";
|
||||
if (rank == 1) {
|
||||
err_msg += " You may need to perform Decode first.";
|
||||
}
|
||||
RETURN_STATUS_UNEXPECTED(err_msg);
|
||||
}
|
||||
}
|
||||
|
@ -164,8 +174,8 @@ Status ValidateImageDtype(const std::string &op_name, DataType dtype) {
|
|||
uint8_t type = dtype.AsCVType();
|
||||
if (type == kCVInvalidType) {
|
||||
std::string type_name = "unknown";
|
||||
if (type < DataType::NUM_OF_TYPES) {
|
||||
type_name = std::string(DataType::kTypeInfo[type].name_);
|
||||
if (dtype.value() < DataType::NUM_OF_TYPES) {
|
||||
type_name = std::string(DataType::kTypeInfo[dtype.value()].name_);
|
||||
}
|
||||
std::string err_msg = op_name + ": Cannot convert [" + type_name + "] to OpenCV type." +
|
||||
" Currently unsupported data type: [uint32, int64, uint64, string]";
|
||||
|
@ -1532,6 +1542,8 @@ Status Pad(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output
|
|||
const int32_t &pad_bottom, const int32_t &pad_left, const int32_t &pad_right, const BorderType &border_types,
|
||||
uint8_t fill_r, uint8_t fill_g, uint8_t fill_b) {
|
||||
try {
|
||||
RETURN_IF_NOT_OK(ValidateImage(input, "Pad", {1, 2, 3, 4, 5, 6, 10, 11, 12}, {2, 3}, {1, 3}));
|
||||
|
||||
// input image
|
||||
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
|
||||
|
||||
|
@ -1539,16 +1551,6 @@ Status Pad(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output
|
|||
RETURN_STATUS_UNEXPECTED("[Internal ERROR] Pad: load image failed.");
|
||||
}
|
||||
|
||||
// validate rank and number channels
|
||||
RETURN_IF_NOT_OK(ValidateImageRank("Pad", input_cv->Rank()));
|
||||
if (input_cv->Rank() == kDefaultImageRank) {
|
||||
if (input_cv->shape()[kChannelIndexHWC] != kDefaultImageChannel &&
|
||||
input_cv->shape()[kChannelIndexHWC] != kMinImageChannel) {
|
||||
RETURN_STATUS_UNEXPECTED("Pad: number of channels for input tensor can only be 1 or 3, got channel: " +
|
||||
std::to_string(input_cv->shape()[kChannelIndexHWC]));
|
||||
}
|
||||
}
|
||||
|
||||
// get the border type in openCV
|
||||
auto b_type = GetCVBorderType(border_types);
|
||||
// output image
|
||||
|
|
|
@ -38,8 +38,7 @@ std::string SizeToString(const std::vector<T> &size) {
|
|||
|
||||
Status PadToSizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
|
||||
IO_CHECK(input, output);
|
||||
RETURN_IF_NOT_OK(ValidateImageDtype("PadToSize", input->type()));
|
||||
RETURN_IF_NOT_OK(ValidateImageRank("PadToSize", input->Rank()));
|
||||
RETURN_IF_NOT_OK(ValidateImage(input, "PadToSize", {1, 2, 3, 4, 5, 6, 10, 11, 12}, {2, 3}, {1, 3}));
|
||||
std::vector<dsize_t> image_size;
|
||||
RETURN_IF_NOT_OK(ImageSize(input, &image_size));
|
||||
CHECK_FAIL_RETURN_SYNTAX_ERROR(
|
||||
|
|
|
@ -62,7 +62,7 @@ Status RandomCropOp::ImagePadding(const std::shared_ptr<Tensor> &input, std::sha
|
|||
CHECK_FAIL_RETURN_UNEXPECTED(
|
||||
pad_top_ < input->shape()[0] * max_ratio && pad_bottom_ < input->shape()[0] * max_ratio &&
|
||||
pad_left_ < input->shape()[1] * max_ratio && pad_right_ < input->shape()[1] * max_ratio,
|
||||
"Pad: padding size is three times bigger than the image size, padding top: " + std::to_string(pad_top_) +
|
||||
"RandomCrop: padding size is three times bigger than the image size, padding top: " + std::to_string(pad_top_) +
|
||||
", padding bottom: " + std::to_string(pad_bottom_) + ", padding pad_left_: " + std::to_string(pad_left_) +
|
||||
", padding padding right:" + std::to_string(pad_right_) + ", image shape: " + std::to_string(input->shape()[0]) +
|
||||
", " + std::to_string(input->shape()[1]));
|
||||
|
@ -125,12 +125,12 @@ Status RandomCropOp::Compute(const TensorRow &input, TensorRow *output) {
|
|||
for (size_t i = 0; i < input.size() - 1; i++) {
|
||||
if (input[i]->Rank() != 2 && input[i]->Rank() != 3) {
|
||||
std::string err_msg =
|
||||
"RandomCropOp: image shape is not <H,W,C> or <H, W>, but got rank:" + std::to_string(input[i]->Rank());
|
||||
"RandomCrop: image shape is not <H,W,C> or <H, W>, but got rank:" + std::to_string(input[i]->Rank());
|
||||
RETURN_STATUS_UNEXPECTED(err_msg);
|
||||
}
|
||||
if (input[i]->shape()[0] != input[i + 1]->shape()[0] || input[i]->shape()[1] != input[i + 1]->shape()[1]) {
|
||||
RETURN_STATUS_UNEXPECTED(
|
||||
"RandomCropOp: Input images in different column must have the same shape, check the output shape in "
|
||||
"RandomCrop: Input images in different column must have the same shape, check the output shape in "
|
||||
"specified 'input_columns' before call this operation.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,16 @@
|
|||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
Status ConvertNumpyToTensor(const py::object &py_obj, TensorRow *output) {
|
||||
std::shared_ptr<Tensor> out;
|
||||
// Python object like bool, int, float, list or tuple can also be converted
|
||||
// to a NumPy array by the following cast, but the data type will be unknown
|
||||
// if it is not a valid NumPy object
|
||||
RETURN_IF_NOT_OK(Tensor::CreateFromNpArray(py_obj.cast<py::array>(), &out));
|
||||
output->push_back(out);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status PyFuncOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
Status ret = Status(StatusCode::kSuccess, "PyFunc Call Succeed");
|
||||
|
@ -57,7 +67,7 @@ Status PyFuncOp::Compute(const TensorRow &input, TensorRow *output) {
|
|||
} else {
|
||||
if (py::isinstance<py::tuple>(ret_py_obj)) {
|
||||
// In case of a n-m mapping, the return value will be a tuple of numpy arrays
|
||||
py::tuple ret_py_tuple = ret_py_obj.cast<py::tuple>();
|
||||
auto ret_py_tuple = ret_py_obj.cast<py::tuple>();
|
||||
// Iterate over two containers simultaneously for memory copy
|
||||
for (size_t i = 0; i < ret_py_tuple.size(); i++) {
|
||||
py::object ret_py_ele = ret_py_tuple[i];
|
||||
|
@ -67,16 +77,11 @@ Status PyFuncOp::Compute(const TensorRow &input, TensorRow *output) {
|
|||
"True, PyFunc may execute time out.";
|
||||
goto TimeoutError;
|
||||
}
|
||||
|
||||
std::shared_ptr<Tensor> out;
|
||||
RETURN_IF_NOT_OK(Tensor::CreateFromNpArray(ret_py_ele.cast<py::array>(), &out));
|
||||
output->push_back(out);
|
||||
RETURN_IF_NOT_OK(ConvertNumpyToTensor(ret_py_ele, output));
|
||||
}
|
||||
} else {
|
||||
// In case of a n-1 mapping, the return value will be a numpy array
|
||||
std::shared_ptr<Tensor> out;
|
||||
RETURN_IF_NOT_OK(Tensor::CreateFromNpArray(ret_py_obj.cast<py::array>(), &out));
|
||||
output->push_back(out);
|
||||
RETURN_IF_NOT_OK(ConvertNumpyToTensor(ret_py_obj, output));
|
||||
}
|
||||
}
|
||||
} catch (const py::error_already_set &e) {
|
||||
|
|
|
@ -2746,14 +2746,6 @@ class _PythonCallable:
|
|||
if result is None:
|
||||
# Invoke original Python callable in master process in case the pool is gone.
|
||||
result = self.py_callable(*args)
|
||||
if isinstance(result, tuple):
|
||||
result_tmp = []
|
||||
for r in result:
|
||||
r = np.array(r) if not isinstance(r, np.ndarray) else r
|
||||
result_tmp.append(r)
|
||||
result = tuple(result_tmp)
|
||||
else:
|
||||
result = np.array(result) if not isinstance(result, np.ndarray) else result
|
||||
return result
|
||||
|
||||
def to_json(self):
|
||||
|
@ -2828,7 +2820,6 @@ def _worker_loop(operations, pipe):
|
|||
"""
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
|
||||
|
||||
while not _main_process_already_exit():
|
||||
_ignore_sigint()
|
||||
|
||||
|
|
|
@ -174,11 +174,12 @@ def test_pad_to_size_check():
|
|||
test_invalid_input(RuntimeError, "target size to pad should be no less than the original image size", size=(5, 5))
|
||||
test_invalid_input(RuntimeError, "sum of offset and original image size should be no more than the target size",
|
||||
(30, 30), (5, 5))
|
||||
test_invalid_input(RuntimeError, "number of channels for input tensor can only be 1 or 3",
|
||||
test_invalid_input(RuntimeError, "Expecting tensor in channel of (1, 3)",
|
||||
data=np.random.random((28, 28, 4)))
|
||||
test_invalid_input(RuntimeError, "input tensor is not in shape of <H,W> or <H,W,C>",
|
||||
test_invalid_input(RuntimeError, "Expecting tensor in dimension of (2, 3)",
|
||||
data=np.random.random(28))
|
||||
test_invalid_input(RuntimeError, "Currently unsupported data type: [uint32, int64, uint64, string]",
|
||||
test_invalid_input(RuntimeError, "Expecting tensor in type of "
|
||||
"(bool, int8, uint8, int16, uint16, int32, float16, float32, float64)",
|
||||
data=np.random.random((28, 28, 3)).astype(np.str))
|
||||
|
||||
|
||||
|
|
|
@ -546,7 +546,7 @@ def test_random_crop_09():
|
|||
with pytest.raises(RuntimeError) as error_info:
|
||||
for _ in data.create_dict_iterator(num_epochs=1, output_numpy=True):
|
||||
pass
|
||||
error_msg = "number of channels for input tensor can only be 1 or 3"
|
||||
error_msg = "Expecting tensor in channel of (1, 3)"
|
||||
assert error_msg in str(error_info.value)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue