Fix padding calculation if interval value is inf (#19383)
This commit is contained in:
parent
81a02c5586
commit
463ae19207
@ -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 {
|
||||||
|
@ -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>;
|
||||||
|
Loading…
Reference in New Issue
Block a user