Fix padding calculation if interval value is inf (#19383)

This commit is contained in:
Pawel Raasz 2023-08-31 09:57:09 +02:00 committed by GitHub
parent 81a02c5586
commit 463ae19207
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 155 additions and 212 deletions

View File

@ -11,6 +11,13 @@
#include "utils.hpp" #include "utils.hpp"
namespace ov { namespace ov {
namespace op { namespace op {
namespace pad {
constexpr bool is_inf_padding(const std::pair<int64_t, int64_t>& pad_bounds) {
return (pad_bounds.first == 0) &&
(ov::util::dim::is_inf_bound(pad_bounds.second) || ov::util::is_max(pad_bounds.second));
}
} // namespace pad
template <class TShape, class TRShape = result_shape_t<TShape>> template <class TShape, class TRShape = result_shape_t<TShape>>
std::vector<TRShape> shape_infer(const util::PadBase* op, std::vector<TRShape> shape_infer(const util::PadBase* op,
const std::vector<TShape>& input_shapes, const std::vector<TShape>& input_shapes,
@ -22,28 +29,19 @@ std::vector<TRShape> shape_infer(const util::PadBase* op,
// Check the shape of pad_value // Check the shape of pad_value
if (pad_mode == PadMode::CONSTANT && input_shapes.size() == 4) { if (pad_mode == PadMode::CONSTANT && input_shapes.size() == 4) {
const auto& pad_value_shape = input_shapes[3]; const auto& pad_value_shape = input_shapes[3];
NODE_VALIDATION_CHECK(op, NODE_SHAPE_INFER_CHECK(op,
input_shapes,
pad_value_shape.rank().compatible(0), pad_value_shape.rank().compatible(0),
"Argument for padding value is not a scalar (shape: ", "Argument for padding value is not a scalar.");
pad_value_shape,
").");
} }
const auto& pads_begin_shape = input_shapes[1]; const auto& pads_begin_shape = input_shapes[1];
const auto& pads_begin_rank = pads_begin_shape.rank(); const auto& pads_begin_rank = pads_begin_shape.rank();
NODE_VALIDATION_CHECK(op, NODE_SHAPE_INFER_CHECK(op, input_shapes, pads_begin_rank.compatible(1), "Argument for pads_begin is not 1D.");
pads_begin_rank.compatible(1),
"Argument for pads_begin is not 1D (shape: ",
pads_begin_rank,
").");
const auto& pads_end_shape = input_shapes[2]; const auto& pads_end_shape = input_shapes[2];
const auto& pads_end_rank = pads_end_shape.rank(); const auto& pads_end_rank = pads_end_shape.rank();
NODE_VALIDATION_CHECK(op, NODE_SHAPE_INFER_CHECK(op, input_shapes, pads_end_rank.compatible(1), "Argument for pads_end is not 1D.");
pads_end_rank.compatible(1),
"Argument for pads_end is not 1D (shape: ",
pads_end_rank,
").");
const auto& arg_shape = input_shapes[0]; const auto& arg_shape = input_shapes[0];
const auto& arg_shape_rank = arg_shape.rank(); const auto& arg_shape_rank = arg_shape.rank();
@ -94,13 +92,15 @@ std::vector<TRShape> shape_infer(const util::PadBase* op,
"of at least 2 at each " "of at least 2 at each "
"spatial axis."); "spatial axis.");
} }
NODE_VALIDATION_CHECK( NODE_SHAPE_INFER_CHECK(
op, op,
input_shapes,
pad_mode != op::PadMode::REFLECT || (cmp::lt(begin_lb, dim_lb) && cmp::lt(end_lb, dim_lb)), pad_mode != op::PadMode::REFLECT || (cmp::lt(begin_lb, dim_lb) && cmp::lt(end_lb, dim_lb)),
"REFLECT padding mode requires that 'pads_begin[D]' and 'pads_end[D]' " "REFLECT padding mode requires that 'pads_begin[D]' and 'pads_end[D]' "
"must be not greater than 'data_shape[D] - 1'."); "must be not greater than 'data_shape[D] - 1'.");
NODE_VALIDATION_CHECK( NODE_SHAPE_INFER_CHECK(
op, op,
input_shapes,
pad_mode != op::PadMode::SYMMETRIC || (cmp::le(begin_lb, dim_lb) && cmp::le(end_lb, dim_lb)), pad_mode != op::PadMode::SYMMETRIC || (cmp::le(begin_lb, dim_lb) && cmp::le(end_lb, dim_lb)),
"SYMMETRIC padding mode requires that 'pads_begin[D]' and 'pads_end[D]' " "SYMMETRIC padding mode requires that 'pads_begin[D]' and 'pads_end[D]' "
"must be not greater than 'data_shape[D]'."); "must be not greater than 'data_shape[D]'.");
@ -111,28 +111,29 @@ std::vector<TRShape> shape_infer(const util::PadBase* op,
if ((pad_dim_diff_lb != 0) || (pad_dim_diff_ub != 0)) { if ((pad_dim_diff_lb != 0) || (pad_dim_diff_ub != 0)) {
using namespace ov::util; using namespace ov::util;
const auto lb = dim::padded(dim_lb, pad_dim_diff_lb); const auto lb = dim::padded(dim_lb, pad_dim_diff_lb);
const auto ub = dim::padded(arg_shape[i].get_max_length(), pad_dim_diff_ub); if (std::is_same<TRShape, PartialShape>::value) {
const auto ub = (pad::is_inf_padding(begin) || pad::is_inf_padding(end))
? dim::inf_bound
: dim::padded(arg_shape[i].get_max_length(), pad_dim_diff_ub);
output_shape.emplace_back(lb, ub); output_shape.emplace_back(lb, ub);
} else {
output_shape.emplace_back(lb);
}
} else { } else {
output_shape.push_back(arg_shape[i]); output_shape.push_back(arg_shape[i]);
} }
} }
} else { } else {
NODE_VALIDATION_CHECK( NODE_SHAPE_INFER_CHECK(
op, op,
pads_begin_rank.is_dynamic() || input_shapes,
static_cast<int64_t>(pads_begin_shape[0].get_length()) <= static_cast<int64_t>(arg_rank_len), pads_begin_rank.is_dynamic() || cmp::le(pads_begin_shape[0].get_length(), arg_rank_len),
"Number of elements of pads_begin must be >= 0 and <= arg rank " "Number of elements of pads_begin must be >= 0 and <= arg rank");
"(pads_begin_shape[0]: ", NODE_SHAPE_INFER_CHECK(
pads_begin_shape[0],
").");
NODE_VALIDATION_CHECK(
op, op,
pads_begin_rank.is_dynamic() || input_shapes,
static_cast<int64_t>(pads_end_shape[0].get_length()) <= static_cast<int64_t>(arg_rank_len), pads_begin_rank.is_dynamic() || cmp::le(pads_end_shape[0].get_length(), arg_rank_len),
"Number of elements of pads_end must be >= 0 and <= arg rank (pads_end_shape[0]: ", "Number of elements of pads_end must be >= 0 and <= arg rank");
pads_end_shape[0],
").");
output_shape.resize(arg_shape_rank.get_length()); output_shape.resize(arg_shape_rank.get_length());
} }
} else { } else {

View File

@ -6,8 +6,10 @@
#include "common_test_utils/test_assertions.hpp" #include "common_test_utils/test_assertions.hpp"
#include "common_test_utils/type_prop.hpp" #include "common_test_utils/type_prop.hpp"
#include "gtest/gtest.h"
#include "openvino/op/broadcast.hpp" #include "openvino/op/broadcast.hpp"
#include "openvino/op/constant.hpp" #include "openvino/op/constant.hpp"
#include "openvino/op/pad.hpp"
#include "openvino/op/shape_of.hpp" #include "openvino/op/shape_of.hpp"
using namespace std; using namespace std;
@ -15,17 +17,17 @@ using namespace ov;
using namespace testing; using namespace testing;
template <class T> template <class T>
class PadTest : public testing::Test {}; class PadTest : public TypePropOpTest<T> {};
TYPED_TEST_SUITE_P(PadTest); TYPED_TEST_SUITE_P(PadTest);
TYPED_TEST_P(PadTest, pad_default_ctor) { TYPED_TEST_P(PadTest, pad_default_ctor) {
const auto arg_shape = PartialShape{{1, 2}, {4, 10}, {3, 8}, {1, 2}}; const auto arg_shape = PartialShape{{1, 2}, {4, 10}, {3, 8}, {1, 2}};
const auto arg = make_shared<ov::op::v0::Parameter>(element::f32, arg_shape); const auto arg = make_shared<op::v0::Parameter>(element::f32, arg_shape);
const auto pads_begin = make_shared<ov::op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 2, 1, 0}); const auto pads_begin = make_shared<op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 2, 1, 0});
const auto pads_end = make_shared<ov::op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 1, 0}); const auto pads_end = make_shared<op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 1, 0});
const auto pad = make_shared<TypeParam>(); const auto pad = this->make_op();
pad->set_arguments(OutputVector{arg, pads_begin, pads_end}); pad->set_arguments(OutputVector{arg, pads_begin, pads_end});
pad->set_pad_mode(op::PadMode::REFLECT); pad->set_pad_mode(op::PadMode::REFLECT);
pad->validate_and_infer_types(); pad->validate_and_infer_types();
@ -35,196 +37,119 @@ TYPED_TEST_P(PadTest, pad_default_ctor) {
} }
TYPED_TEST_P(PadTest, pad_arg_pad_value_type_mismatch) { TYPED_TEST_P(PadTest, pad_arg_pad_value_type_mismatch) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::i64, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::i64, Shape{1});
auto arg_pad_value = make_shared<ov::op::v0::Parameter>(element::f16, Shape{1}); auto arg_pad_value = make_shared<op::v0::Parameter>(element::f16, Shape{1});
try { OV_EXPECT_THROW(ignore = this->make_op(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT); NodeValidationFailure,
HasSubstr("Argument element types do not match (input arg element type:"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect arg_pad_value type exception not handled";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Argument element types do not match (input arg element type:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_arg_pad_value_shape_not_compatible) { TYPED_TEST_P(PadTest, pad_arg_pad_value_shape_not_compatible) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::i64, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::i64, Shape{1});
auto arg_pad_value = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1}); auto arg_pad_value = make_shared<op::v0::Parameter>(element::f32, Shape{1});
try { OV_EXPECT_THROW(ignore = this->make_op(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT); NodeValidationFailure,
HasSubstr("Argument for padding value is not a scalar"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect arg_pad_value shape exception not handled";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Argument for padding value is not a scalar (shape:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_pads_begin_shape_not_1D) { TYPED_TEST_P(PadTest, pad_pads_begin_shape_not_1D) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1, 2}); auto pads_begin = make_shared<op::v0::Parameter>(element::i64, Shape{1, 2});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::i64, Shape{1});
try { OV_EXPECT_THROW(ignore = this->make_op(arg, pads_begin, pads_end, op::PadMode::SYMMETRIC),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::SYMMETRIC); NodeValidationFailure,
HasSubstr("Argument for pads_begin is not 1D"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect pads_begin shape exception not handled";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Argument for pads_begin is not 1D (shape:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_pads_end_shape_not_1D) { TYPED_TEST_P(PadTest, pad_pads_end_shape_not_1D) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::i64, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1, 2}); auto pads_end = make_shared<op::v0::Parameter>(element::i64, Shape{1, 2});
try { OV_EXPECT_THROW(ignore = this->make_op(arg, pads_begin, pads_end, op::PadMode::SYMMETRIC),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::SYMMETRIC); NodeValidationFailure,
HasSubstr("Argument for pads_end is not 1D"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect pads_end shape exception not handled";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Argument for pads_end is not 1D (shape:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_pads_begin_size_not_correct) { TYPED_TEST_P(PadTest, pad_pads_begin_size_not_correct) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i64, Shape{4}); auto pads_begin = make_shared<op::v0::Parameter>(element::i64, Shape{4});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::i64, Shape{1});
try { OV_EXPECT_THROW(ignore = this->make_op(arg, pads_begin, pads_end, op::PadMode::SYMMETRIC),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::SYMMETRIC); NodeValidationFailure,
HasSubstr("Number of elements of pads_begin must be >= 0 and <= arg rank"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect pads_begin size exception not handled";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("Number of elements of pads_begin must be >= 0 and <= arg "
"rank (pads_begin_shape[0]:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_pads_end_size_not_correct) { TYPED_TEST_P(PadTest, pad_pads_end_size_not_correct) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::i64, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i64, Shape{4}); auto pads_end = make_shared<op::v0::Parameter>(element::i64, Shape{4});
auto arg_pad_value = make_shared<ov::op::v0::Parameter>(element::f32, Shape{}); auto arg_pad_value = make_shared<op::v0::Parameter>(element::f32, Shape{});
try { OV_EXPECT_THROW(ignore = this->make_op(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT); NodeValidationFailure,
HasSubstr("Number of elements of pads_end must be >= 0 and <= arg rank"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect pads_end size exception not handled";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(
error.what(),
std::string("Number of elements of pads_end must be >= 0 and <= arg rank (pads_end_shape[0]:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_arg_pads_begin_incompatible_type) { TYPED_TEST_P(PadTest, pad_arg_pads_begin_incompatible_type) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::f32, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::i64, Shape{1});
try { OV_EXPECT_THROW(this->make_op(arg, pads_begin, pads_end, op::PadMode::REFLECT),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::REFLECT); NodeValidationFailure,
HasSubstr("pads_begin must be an integral number, but is:"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect pad_begin type exception not handled";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("pads_begin must be an integral number, but is:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_arg_pads_end_incompatible_type) { TYPED_TEST_P(PadTest, pad_arg_pads_end_incompatible_type) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i64, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::i64, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::f32, Shape{1});
try { OV_EXPECT_THROW(this->make_op(arg, pads_begin, pads_end, op::PadMode::REFLECT),
auto pad = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::REFLECT); NodeValidationFailure,
HasSubstr("pads_end must be an integral number, but is:"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect pads_end type exception not thrown";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("pads_end must be an integral number, but is:"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_deduce_too_small_for_edge) { TYPED_TEST_P(PadTest, pad_deduce_too_small_for_edge) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 5, 0, 2}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 5, 0, 2});
auto pads_begin = make_shared<ov::op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3}); auto pads_begin = make_shared<op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3});
auto pads_end = make_shared<ov::op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3}); auto pads_end = make_shared<op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3});
auto arg_pad_value = make_shared<ov::op::v0::Parameter>(element::f32, Shape{}); auto arg_pad_value = make_shared<op::v0::Parameter>(element::f32, Shape{});
try { OV_EXPECT_THROW(this->make_op(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::EDGE),
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::EDGE); NodeValidationFailure,
HasSubstr("EDGE padding mode requires an input of dimension of at least 1 at each spatial axis"));
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect input shape exception for EDGE mode not thrown";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("EDGE padding mode requires an input of dimension of at "
"least 1 at each spatial axis"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_deduce_too_small_for_reflect) { TYPED_TEST_P(PadTest, pad_deduce_too_small_for_reflect) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, Shape{1, 5, 1, 2}); auto arg = make_shared<op::v0::Parameter>(element::f32, Shape{1, 5, 1, 2});
auto pads_begin = make_shared<ov::op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3}); auto pads_begin = make_shared<op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3});
auto pads_end = make_shared<ov::op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3}); auto pads_end = make_shared<op::v0::Constant>(element::i64, Shape{4}, std::vector<int64_t>{0, 1, 2, 3});
auto arg_pad_value = make_shared<ov::op::v0::Parameter>(element::f32, Shape{}); auto arg_pad_value = make_shared<op::v0::Parameter>(element::f32, Shape{});
try { OV_EXPECT_THROW(
auto pad_v1 = make_shared<TypeParam>(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::REFLECT); this->make_op(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::REFLECT),
NodeValidationFailure,
// Should have thrown, so fail if it didn't HasSubstr("REFLECT padding mode requires an input of dimension of at least 2 at each spatial axis"));
FAIL() << "Incorrect input shape exception for REFLECT mode not thrown";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("REFLECT padding mode requires an input of dimension of "
"at least 2 at each spatial axis"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
} }
TYPED_TEST_P(PadTest, pad_pads_end_got_negative_value) { TYPED_TEST_P(PadTest, pad_pads_end_got_negative_value) {
auto arg_shape = PartialShape{-1, {0, 10}, {2, -1}, {2, 8}, {3, 10}, 5}; auto arg_shape = PartialShape{-1, {0, 10}, {2, -1}, {2, 8}, {3, 10}, 5};
set_shape_labels(arg_shape, 10); set_shape_labels(arg_shape, 10);
const auto arg = std::make_shared<ov::op::v0::Parameter>(element::f32, arg_shape); const auto arg = std::make_shared<op::v0::Parameter>(element::f32, arg_shape);
const auto pads_begin = ov::op::v0::Constant::create(element::i64, Shape{6}, {2, 0, 1, 3, 2, 1}); const auto pads_begin = op::v0::Constant::create(element::i64, Shape{6}, {2, 0, 1, 3, 2, 1});
const auto pads_end = ov::op::v0::Constant::create(element::i64, Shape{6}, {-3, -2, -2, -3, -1, -3}); const auto pads_end = op::v0::Constant::create(element::i64, Shape{6}, {-3, -2, -2, -3, -1, -3});
const auto pad = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::REFLECT); const auto pad = this->make_op(arg, pads_begin, pads_end, op::PadMode::REFLECT);
EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({-1, {0, 8}, {1, -1}, {2, 8}, {4, 11}, 3})); EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({-1, {0, 8}, {1, -1}, {2, 8}, {4, 11}, 3}));
EXPECT_THAT(get_shape_labels(pad->get_output_partial_shape(0)), EXPECT_THAT(get_shape_labels(pad->get_output_partial_shape(0)),
@ -234,9 +159,9 @@ TYPED_TEST_P(PadTest, pad_pads_end_got_negative_value) {
TYPED_TEST_P(PadTest, pad_pads_begin_got_negative_value) { TYPED_TEST_P(PadTest, pad_pads_begin_got_negative_value) {
auto arg_shape = PartialShape{-1, {0, 10}, {2, -1}, {2, 8}, {3, 10}, 5}; auto arg_shape = PartialShape{-1, {0, 10}, {2, -1}, {2, 8}, {3, 10}, 5};
set_shape_labels(arg_shape, 10); set_shape_labels(arg_shape, 10);
const auto arg = std::make_shared<ov::op::v0::Parameter>(element::f32, arg_shape); const auto arg = std::make_shared<op::v0::Parameter>(element::f32, arg_shape);
const auto pads_begin = ov::op::v0::Constant::create(element::i64, Shape{6}, {-1, -1, -2, -3, -8, -4}); const auto pads_begin = op::v0::Constant::create(element::i64, Shape{6}, {-1, -1, -2, -3, -8, -4});
const auto pads_end = ov::op::v0::Constant::create(element::i64, Shape{6}, {0, 2, 0, 3, 5, 4}); const auto pads_end = op::v0::Constant::create(element::i64, Shape{6}, {0, 2, 0, 3, 5, 4});
const auto pad = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::REFLECT); const auto pad = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::REFLECT);
EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({-1, {1, 11}, {0, -1}, {2, 8}, {0, 7}, 5})); EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({-1, {1, 11}, {0, -1}, {2, 8}, {0, 7}, 5}));
@ -245,12 +170,12 @@ TYPED_TEST_P(PadTest, pad_pads_begin_got_negative_value) {
} }
TYPED_TEST_P(PadTest, pad_dynamic_output_with_dynamic_rank) { TYPED_TEST_P(PadTest, pad_dynamic_output_with_dynamic_rank) {
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, PartialShape::dynamic()); auto arg = make_shared<op::v0::Parameter>(element::f32, PartialShape::dynamic());
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i32, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::i32, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i32, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::i32, Shape{1});
auto arg_pad_value = ov::op::v0::Constant::create(element::f32, Shape{}, {0}); auto arg_pad_value = op::v0::Constant::create(element::f32, Shape{}, {0});
auto pad = make_shared<TypeParam>(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT); auto pad = this->make_op(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT);
ASSERT_EQ(pad->get_output_partial_shape(0), PartialShape::dynamic()); ASSERT_EQ(pad->get_output_partial_shape(0), PartialShape::dynamic());
} }
@ -279,25 +204,23 @@ TYPED_TEST_P(PadTest, pad_any_dim_for_padding_reflect) {
TYPED_TEST_P(PadTest, pad_any_dim_for_padding_edge) { TYPED_TEST_P(PadTest, pad_any_dim_for_padding_edge) {
auto arg_shape = PartialShape{1, {0, 48}, -1, {20, -1}, {5, -1}, 10, 12}; auto arg_shape = PartialShape{1, {0, 48}, -1, {20, -1}, {5, -1}, 10, 12};
set_shape_labels(arg_shape, 10); set_shape_labels(arg_shape, 10);
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, arg_shape); auto arg = make_shared<op::v0::Parameter>(element::f32, arg_shape);
auto pads_begin = auto pads_begin = make_shared<op::v0::Constant>(element::i64, Shape{7}, std::vector<int64_t>{1, 2, 1, 2, 0, 0, 0});
make_shared<ov::op::v0::Constant>(element::i64, Shape{7}, std::vector<int64_t>{1, 2, 1, 2, 0, 0, 0}); auto pads_end = make_shared<op::v0::Constant>(element::i64, Shape{7}, std::vector<int64_t>{0, 3, 0, 1, 0, 5, 0});
auto pads_end =
make_shared<ov::op::v0::Constant>(element::i64, Shape{7}, std::vector<int64_t>{0, 3, 0, 1, 0, 5, 0});
auto pad = make_shared<TypeParam>(arg, pads_begin, pads_end, op::PadMode::EDGE); auto pad = this->make_op(arg, pads_begin, pads_end, op::PadMode::EDGE);
EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({2, {5, 53}, {1, -1}, {23, -1}, {5, -1}, 15, 12})); EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({2, {5, 53}, {1, -1}, {23, -1}, {5, -1}, 15, 12}));
EXPECT_THAT(get_shape_labels(pad->get_output_partial_shape(0)), EXPECT_THAT(get_shape_labels(pad->get_output_partial_shape(0)),
ElementsAre(ov::no_label, ov::no_label, ov::no_label, ov::no_label, 14, ov::no_label, 16)); ElementsAre(ov::no_label, ov::no_label, ov::no_label, ov::no_label, 14, ov::no_label, 16));
} }
TYPED_TEST_P(PadTest, pad_dynamic_input_type_with_static_value) { TYPED_TEST_P(PadTest, pad_dynamic_input_type_with_static_value) {
auto arg = make_shared<ov::op::v0::Parameter>(element::dynamic, Shape{1, 2, 3}); auto arg = make_shared<op::v0::Parameter>(element::dynamic, Shape{1, 2, 3});
auto pads_begin = make_shared<ov::op::v0::Parameter>(element::i32, Shape{1}); auto pads_begin = make_shared<op::v0::Parameter>(element::i32, Shape{1});
auto pads_end = make_shared<ov::op::v0::Parameter>(element::i32, Shape{1}); auto pads_end = make_shared<op::v0::Parameter>(element::i32, Shape{1});
auto arg_pad_value = ov::op::v0::Constant::create(element::f32, Shape{}, {0}); auto arg_pad_value = op::v0::Constant::create(element::f32, Shape{}, {0});
auto pad = make_shared<TypeParam>(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT); auto pad = this->make_op(arg, pads_begin, pads_end, arg_pad_value, op::PadMode::CONSTANT);
EXPECT_EQ(pad->get_output_element_type(0), element::f32); EXPECT_EQ(pad->get_output_element_type(0), element::f32);
EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape::dynamic(3)); EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape::dynamic(3));
} }
@ -310,11 +233,11 @@ TYPED_TEST_P(PadTest, pad_preserve_partial_values_and_labels_via_evaluates_bound
set_shape_labels(begin_shape, 20); set_shape_labels(begin_shape, 20);
set_shape_labels(end_shape, 30); set_shape_labels(end_shape, 30);
auto arg = make_shared<ov::op::v0::Parameter>(element::f32, arg_shape); auto arg = make_shared<op::v0::Parameter>(element::f32, arg_shape);
auto s_begin = make_shared<op::v0::ShapeOf>(make_shared<ov::op::v0::Parameter>(element::i64, begin_shape)); auto s_begin = make_shared<op::v0::ShapeOf>(make_shared<op::v0::Parameter>(element::i64, begin_shape));
auto s_end = make_shared<op::v0::ShapeOf>(make_shared<ov::op::v0::Parameter>(element::i64, end_shape)); auto s_end = make_shared<op::v0::ShapeOf>(make_shared<op::v0::Parameter>(element::i64, end_shape));
auto pad = make_shared<TypeParam>(arg, s_begin, s_end, op::PadMode::EDGE); auto pad = this->make_op(arg, s_begin, s_end, op::PadMode::EDGE);
EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({{4, 7}, {2, 5}, {2, 6}})); EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({{4, 7}, {2, 5}, {2, 6}}));
EXPECT_THAT(get_shape_labels(pad->get_output_partial_shape(0)), ElementsAre(ov::no_label, 11, ov::no_label)); EXPECT_THAT(get_shape_labels(pad->get_output_partial_shape(0)), ElementsAre(ov::no_label, 11, ov::no_label));
@ -323,20 +246,38 @@ TYPED_TEST_P(PadTest, pad_preserve_partial_values_and_labels_via_evaluates_bound
TYPED_TEST_P(PadTest, pad_preserve_partial_values_and_labels_on_inputs) { TYPED_TEST_P(PadTest, pad_preserve_partial_values_and_labels_on_inputs) {
auto arg_shape = PartialShape{1, {2, 5}, {1, 3}}; auto arg_shape = PartialShape{1, {2, 5}, {1, 3}};
set_shape_labels(arg_shape, 10); set_shape_labels(arg_shape, 10);
auto arg = make_shared<ov::op::v0::Parameter>(element::i32, arg_shape); auto arg = make_shared<op::v0::Parameter>(element::i32, arg_shape);
auto s = make_shared<op::v0::ShapeOf>(arg); auto s = make_shared<op::v0::ShapeOf>(arg);
auto pads_begin = make_shared<ov::op::v0::Constant>(element::i64, Shape{1}, std::vector<int64_t>{1}); auto pads_begin = make_shared<op::v0::Constant>(element::i64, Shape{1}, std::vector<int64_t>{1});
auto pads_end = make_shared<ov::op::v0::Constant>(element::i64, Shape{1}, std::vector<int64_t>{2}); auto pads_end = make_shared<op::v0::Constant>(element::i64, Shape{1}, std::vector<int64_t>{2});
auto pad = make_shared<TypeParam>(s, pads_begin, pads_end, op::PadMode::EDGE); auto pad = this->make_op(s, pads_begin, pads_end, op::PadMode::EDGE);
auto param = make_shared<ov::op::v0::Parameter>(element::f32, PartialShape{1}); auto param = make_shared<op::v0::Parameter>(element::f32, PartialShape{1});
auto bc = std::make_shared<op::v3::Broadcast>(param, pad, op::BroadcastType::BIDIRECTIONAL); auto bc = std::make_shared<op::v3::Broadcast>(param, pad, op::BroadcastType::BIDIRECTIONAL);
EXPECT_EQ(bc->get_output_partial_shape(0), PartialShape({1, 1, {2, 5}, {1, 3}, {1, 3}, {1, 3}})); EXPECT_EQ(bc->get_output_partial_shape(0), PartialShape({1, 1, {2, 5}, {1, 3}, {1, 3}, {1, 3}}));
EXPECT_THAT(get_shape_labels(bc->get_output_partial_shape(0)), ElementsAre(10, 10, 11, 12, 12, 12)); EXPECT_THAT(get_shape_labels(bc->get_output_partial_shape(0)), ElementsAre(10, 10, 11, 12, 12, 12));
} }
TYPED_TEST_P(PadTest, pad_begin_and_end_has_inf_interval_as_bounds) {
auto arg_shape = PartialShape{9, {3, 5}, {3, 5}, {3, 4}, {3, 4}};
auto begin_shape = PartialShape{-1, {0, 2}, -1, -1, {0, 1}};
auto end_shape = PartialShape{-1, -1, {0, 2}, {0, 1}, -1};
set_shape_labels(arg_shape, 10);
set_shape_labels(begin_shape, 20);
set_shape_labels(end_shape, 30);
auto arg = make_shared<op::v0::Parameter>(element::f32, arg_shape);
auto s_begin = make_shared<op::v0::ShapeOf>(make_shared<op::v0::Parameter>(element::i32, begin_shape));
auto s_end = make_shared<op::v0::ShapeOf>(make_shared<op::v0::Parameter>(element::i32, end_shape));
auto pad = this->make_op(arg, s_begin, s_end, op::PadMode::CONSTANT);
EXPECT_EQ(pad->get_output_partial_shape(0), PartialShape({{9, -1}, {3, -1}, {3, -1}, {3, -1}, {3, -1}}));
EXPECT_THAT(get_shape_labels(pad->get_output_partial_shape(0)), Each(ov::no_label));
}
REGISTER_TYPED_TEST_SUITE_P(PadTest, REGISTER_TYPED_TEST_SUITE_P(PadTest,
pad_default_ctor, pad_default_ctor,
pad_arg_pad_value_type_mismatch, pad_arg_pad_value_type_mismatch,
@ -357,6 +298,7 @@ REGISTER_TYPED_TEST_SUITE_P(PadTest,
pad_any_dim_for_padding_edge, pad_any_dim_for_padding_edge,
pad_dynamic_input_type_with_static_value, pad_dynamic_input_type_with_static_value,
pad_preserve_partial_values_and_labels_via_evaluates_bounds, pad_preserve_partial_values_and_labels_via_evaluates_bounds,
pad_begin_and_end_has_inf_interval_as_bounds,
pad_preserve_partial_values_and_labels_on_inputs); pad_preserve_partial_values_and_labels_on_inputs);
using PadOpTypes = Types<op::v1::Pad, op::v12::Pad>; using PadOpTypes = Types<op::v1::Pad, op::v12::Pad>;