Review shape inference of ExtractImagesPatches (#18771)

* Review shape inference of ExtractImagesPatches
- Check static and dynamic shapes propagation
- Check label propagation
- Review template implementation of `shape_infer function
- Add unit tests.

* Add additional test to check padding calc
This commit is contained in:
Pawel Raasz authored and GitHub committed 2023-07-26 21:49:48 +04:00
1 parent bb3c9aa9a7
commit 32f2868a5b
5 files changed
+382 -130

No files matched your search

@@ -2,94 +2,81 @@
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <openvino/op/extractimagepatches.hpp>
#include "dimension_util.hpp"
#include "openvino/op/extractimagepatches.hpp"
#include "utils.hpp"
namespace ov {
namespace op {
namespace v3 {
int32_t inline calc_shape_padding(const int32_t input,
const int32_t rate,
const int32_t stride,
const int32_t patch_size,
const PadType type) {
int32_t out = 0;
if (type == PadType::VALID) {
out = (input - rate * (patch_size - 1) - 1) / stride + 1;
} else {
out = 1 + (input - 1) / stride;
}
return out < 0 ? 0 : out;
}
template <class T, class TRShape = result_shape_t<T>>
std::vector<TRShape> shape_infer(const ExtractImagePatches* op, const std::vector<T>& input_shapes) {
NODE_VALIDATION_CHECK(op, input_shapes.size() == 1);
using DimType = typename T::value_type;
using namespace ov::util;
using TDim = typename T::value_type;
constexpr size_t num_spatial_dim = 2;
constexpr auto is_zero = cmp::Less<size_t>(1);
const auto& input_shape = input_shapes[0];
auto output_shapes = std::vector<TRShape>(1);
auto& output_shape = output_shapes[0];
output_shape.resize(4);
NODE_VALIDATION_CHECK(op, input_shape.rank().compatible(4), "input tensor must be 4D tensor.");
NODE_SHAPE_INFER_CHECK(op, input_shapes, input_shape.rank().compatible(4), "input tensor must be 4D tensor.");
const auto& sizes = op->get_sizes();
NODE_VALIDATION_CHECK(op,
op->get_sizes().size() == 2,
sizes.size() == num_spatial_dim,
"Attribute sizes should be in [size_rows, size_cols] format.");
const auto& strides = op->get_strides();
NODE_VALIDATION_CHECK(op,
op->get_strides().size() == 2,
strides.size() == num_spatial_dim,
"Attribute strides should be in [stride_rows, stride_cols] format.");
NODE_VALIDATION_CHECK(op,
op->get_strides()[0] > 0 && op->get_strides()[1] > 0,
std::none_of(strides.begin(), strides.end(), is_zero),
"Attribute strides should be strictly greater than zeros in values.");
const auto& rates = op->get_rates();
NODE_VALIDATION_CHECK(op,
op->get_rates().size() == 2,
rates.size() == num_spatial_dim,
"Attribute rates should be in [rate_rows, rate_cols] format.");
NODE_VALIDATION_CHECK(op,
op->get_rates()[0] > 0 && op->get_rates()[1] > 0,
std::none_of(rates.begin(), rates.end(), is_zero),
"Attribute rates should be strictly greater than zeros in values.");
NODE_VALIDATION_CHECK(op,
op->get_auto_pad() == PadType::VALID || op->get_auto_pad() == PadType::SAME_LOWER ||
op->get_auto_pad() == PadType::SAME_UPPER,
"Attribute padding should be in either valid or same_lower or same_upper.");
const auto& pad_type = op->get_auto_pad();
NODE_VALIDATION_CHECK(
op,
pad_type == PadType::VALID || pad_type == PadType::SAME_LOWER || pad_type == PadType::SAME_UPPER,
"Attribute padding should be in either valid or same_lower or same_upper.");
if (input_shape.rank().is_static()) {
// Determine batch & output_depth
output_shape[0] = input_shape[0];
output_shape[1] = input_shape[1] * op->get_sizes()[0] * op->get_sizes()[1];
// Determine spatial shape
if (input_shape[2].is_static() && input_shape[3].is_static()) {
int32_t input_rows = static_cast<int32_t>(input_shape[2].get_length());
int32_t input_cols = static_cast<int32_t>(input_shape[3].get_length());
int32_t out_rows(0);
int32_t out_cols(0);
if (input_rows == 0 || input_cols == 0) {
output_shape = input_shape;
return output_shapes;
const auto num_non_spatial_dims = input_shape.size() - num_spatial_dim;
auto out_it = std::copy_n(input_shape.begin(), num_non_spatial_dims, std::back_inserter(output_shape));
output_shape[1] *=
std::accumulate(sizes.begin(), sizes.end(), static_cast<size_t>(1), std::multiplies<size_t>());
auto stride_it = strides.cbegin();
if (pad_type == PadType::VALID) {
auto size_it = sizes.cbegin();
auto rate_it = rates.cbegin();
for (size_t i = num_non_spatial_dims; i < input_shape.size(); ++i, ++stride_it, ++size_it, ++rate_it) {
out_it = dim::ceil_div(input_shape[i] - ((*rate_it) * (*size_it - 1)), *stride_it);
}
out_rows = calc_shape_padding(input_rows,
static_cast<int32_t>(op->get_rates()[0]),
static_cast<int32_t>(op->get_strides()[0]),
static_cast<int32_t>(op->get_sizes()[0]),
op->get_auto_pad());
out_cols = calc_shape_padding(input_cols,
static_cast<int32_t>(op->get_rates()[1]),
static_cast<int32_t>(op->get_strides()[1]),
static_cast<int32_t>(op->get_sizes()[1]),
op->get_auto_pad());
auto out_rows_cast = static_cast<typename DimType::value_type>(out_rows);
auto out_cols_cast = static_cast<typename DimType::value_type>(out_cols);
output_shape[2] = out_rows_cast;
output_shape[3] = out_cols_cast;
} else {
std::transform(input_shape.begin() + num_non_spatial_dims,
input_shape.end(),
stride_it,
out_it,
&dim::ceil_div<TDim>);
}
} else {
output_shape.resize(4);
}
return output_shapes;
}
+25 -23
View File
@@ -2,23 +2,20 @@
// SPDX-License-Identifier: Apache-2.0
//
#include "ngraph/op/extractimagepatches.hpp"
#include <extract_image_patches_shape_inference.hpp>
#include "openvino/op/extractimagepatches.hpp"
#include "extract_image_patches_shape_inference.hpp"
#include "itt.hpp"
#include "ngraph/attribute_visitor.hpp"
#include "openvino/core/attribute_visitor.hpp"
using namespace std;
using namespace ngraph;
// ExtractImagePatches v3
op::v3::ExtractImagePatches::ExtractImagePatches(const Output<Node>& image,
const ov::Shape& sizes,
const Strides& strides,
const ov::Shape& rates,
const PadType& auto_pad)
namespace ov {
namespace op {
namespace v3 {
ExtractImagePatches::ExtractImagePatches(const Output<Node>& image,
const ov::Shape& sizes,
const Strides& strides,
const ov::Shape& rates,
const PadType& auto_pad)
: Op({image}),
m_patch_sizes(sizes),
m_patch_movement_strides(strides),
@@ -27,16 +24,17 @@ op::v3::ExtractImagePatches::ExtractImagePatches(const Output<Node>& image,
constructor_validate_and_infer_types();
}
void op::v3::ExtractImagePatches::validate_and_infer_types() {
void ExtractImagePatches::validate_and_infer_types() {
OV_OP_SCOPE(v3_ExtractImagePatches_validate_and_infer_types);
std::vector<PartialShape> input_shapes = {get_input_partial_shape(0)};
const auto input_shapes = std::vector<PartialShape>{get_input_partial_shape(0)};
const auto output_shapes = shape_infer(this, input_shapes);
if (output_shapes[0].is_dynamic())
set_input_is_relevant_to_shape(0);
set_output_type(0, get_input_element_type(0), output_shapes[0]);
}
bool op::v3::ExtractImagePatches::visit_attributes(AttributeVisitor& visitor) {
bool ExtractImagePatches::visit_attributes(AttributeVisitor& visitor) {
OV_OP_SCOPE(v3_ExtractImagePatches_visit_attributes);
visitor.on_attribute("sizes", m_patch_sizes);
visitor.on_attribute("strides", m_patch_movement_strides);
@@ -45,12 +43,16 @@ bool op::v3::ExtractImagePatches::visit_attributes(AttributeVisitor& visitor) {
return true;
}
shared_ptr<Node> op::v3::ExtractImagePatches::clone_with_new_inputs(const OutputVector& new_args) const {
std::shared_ptr<Node> ExtractImagePatches::clone_with_new_inputs(const OutputVector& new_args) const {
OV_OP_SCOPE(v3_ExtractImagePatches_clone_with_new_inputs);
check_new_args_count(this, new_args);
return make_shared<op::v3::ExtractImagePatches>(new_args.at(0),
m_patch_sizes,
m_patch_movement_strides,
m_patch_selection_rates,
m_padding);
return std::make_shared<ExtractImagePatches>(new_args.at(0),
m_patch_sizes,
m_patch_movement_strides,
m_patch_selection_rates,
m_padding);
}
} // namespace v3
} // namespace op
} // namespace ov
+249 -24
View File
@@ -2,15 +2,36 @@
// SPDX-License-Identifier: Apache-2.0
//
#include "openvino/op/extractimagepatches.hpp"
#include <gtest/gtest.h>
#include "common_test_utils/test_assertions.hpp"
#include "common_test_utils/type_prop.hpp"
#include "gtest/gtest.h"
#include "ngraph/ngraph.hpp"
using namespace std;
using namespace ngraph;
using namespace ov;
using namespace testing;
TEST(type_prop, extractimagepatches_default_ctor) {
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto padtype_padding = op::PadType::VALID;
auto op = make_shared<op::v3::ExtractImagePatches>();
op->set_argument(0, data);
op->set_sizes({3, 3});
op->set_strides({5, 5});
op->set_rates({1, 1});
op->set_auto_pad(padtype_padding);
op->validate_and_infer_types();
EXPECT_EQ(op->get_input_size(), 1);
EXPECT_EQ(op->get_output_element_type(0), element::i32);
EXPECT_EQ(op->get_output_shape(0), (Shape{64, 27, 2, 2}));
}
TEST(type_prop, extractimagepatches_i32) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -22,7 +43,7 @@ TEST(type_prop, extractimagepatches_i32) {
}
TEST(type_prop, extractimagepatches_i64) {
auto data = make_shared<op::Parameter>(element::i64, Shape{64, 3, 10, 10});
auto data = make_shared<op::v0::Parameter>(element::i64, Shape{64, 3, 12, 12});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -34,7 +55,7 @@ TEST(type_prop, extractimagepatches_i64) {
}
TEST(type_prop, extractimagepatches_rates_change) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 33, 43});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{2, 2};
@@ -42,11 +63,13 @@ TEST(type_prop, extractimagepatches_rates_change) {
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 2, 2}));
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 6, 8}));
}
TEST(type_prop, extractimagepatches_input_shape_change) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 9, 9});
auto data_shape = PartialShape{64, 3, 9, 9};
set_shape_labels(data_shape, 10);
auto data = make_shared<op::v0::Parameter>(element::i32, data_shape);
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{2, 2};
@@ -55,10 +78,14 @@ TEST(type_prop, extractimagepatches_input_shape_change) {
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 1, 1}));
EXPECT_THAT(get_shape_labels(extractimagepatches->get_output_partial_shape(0)), ElementsAre(10, 0, 0, 0));
}
TEST(type_prop, extractimagepatches_dynamic_shape) {
auto data = make_shared<op::Parameter>(element::i32, PartialShape::dynamic(4));
auto data_shape = PartialShape::dynamic(4);
set_shape_labels(data_shape, 10);
auto data = make_shared<op::v0::Parameter>(element::i32, data_shape);
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{2, 2};
@@ -66,11 +93,12 @@ TEST(type_prop, extractimagepatches_dynamic_shape) {
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_TRUE(extractimagepatches->get_output_partial_shape(0).same_scheme(PartialShape::dynamic(4)));
EXPECT_EQ(extractimagepatches->get_output_partial_shape(0), PartialShape::dynamic(4));
EXPECT_THAT(get_shape_labels(extractimagepatches->get_output_partial_shape(0)), ElementsAre(10, 0, 0, 0));
}
TEST(type_prop, extractimagepatches_dynamic_batch_shape) {
auto data = make_shared<op::Parameter>(element::i32, PartialShape{Dimension::dynamic(), 3, 10, 10});
auto data = make_shared<op::v0::Parameter>(element::i32, PartialShape{Dimension::dynamic(), 3, 14, 23});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -78,12 +106,26 @@ TEST(type_prop, extractimagepatches_dynamic_batch_shape) {
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_TRUE(
extractimagepatches->get_output_partial_shape(0).same_scheme(PartialShape{Dimension::dynamic(), 27, 2, 2}));
EXPECT_EQ(extractimagepatches->get_output_partial_shape(0), PartialShape({-1, 27, 3, 5}));
}
TEST(type_prop, extractimagepatches_interval_shape_and_labels) {
auto data_shape = PartialShape{{1, 10}, {3, 4}, {10, 51}, {13, 71}};
set_shape_labels(data_shape, 10);
auto data = make_shared<op::v0::Parameter>(element::i32, data_shape);
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
auto padtype_padding = op::PadType::VALID;
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_EQ(extractimagepatches->get_output_partial_shape(0), PartialShape({{1, 10}, {27, 36}, {2, 10}, {3, 14}}));
EXPECT_THAT(get_shape_labels(extractimagepatches->get_output_partial_shape(0)), ElementsAre(10, 0, 0, 0));
}
TEST(type_prop, extractimagepatches_padding_same_lower1) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 31, 27});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -91,11 +133,11 @@ TEST(type_prop, extractimagepatches_padding_same_lower1) {
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 2, 2}));
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 7, 6}));
}
TEST(type_prop, extractimagepatches_padding_same_lower2) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 9, 9});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 9, 9});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -106,7 +148,7 @@ TEST(type_prop, extractimagepatches_padding_same_lower2) {
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 2, 2}));
}
TEST(type_prop, extractimagepatches_padding_same_upper) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 11, 11});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 23, 11});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -114,11 +156,11 @@ TEST(type_prop, extractimagepatches_padding_same_upper) {
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 3, 3}));
EXPECT_EQ(extractimagepatches->get_output_shape(0), (Shape{64, 27, 5, 3}));
}
TEST(type_prop, extractimagepatches_padding_same_upper2) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 6, 11});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 6, 11});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -130,7 +172,7 @@ TEST(type_prop, extractimagepatches_padding_same_upper2) {
}
TEST(type_prop, extractimagepatches_zero_dim_inputs) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 0, 0, 0});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 0, 0, 0});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -142,7 +184,7 @@ TEST(type_prop, extractimagepatches_zero_dim_inputs) {
}
TEST(type_prop, extractimagepatches_large_stride_valid_padding) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto sizes = Shape{3, 3};
auto strides = Strides{15, 15};
auto rates = Shape{1, 1};
@@ -154,7 +196,7 @@ TEST(type_prop, extractimagepatches_large_stride_valid_padding) {
}
TEST(type_prop, extractimagepatches_large_stride_same_padding) {
auto data = make_shared<op::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto data = make_shared<op::v0::Parameter>(element::i32, Shape{64, 3, 10, 10});
auto sizes = Shape{3, 3};
auto strides = Strides{15, 15};
auto rates = Shape{1, 1};
@@ -166,7 +208,7 @@ TEST(type_prop, extractimagepatches_large_stride_same_padding) {
}
TEST(type_prop, extractimagepatches_dyn) {
auto data = make_shared<op::Parameter>(element::i64, PartialShape::dynamic());
auto data = make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic());
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
@@ -174,5 +216,188 @@ TEST(type_prop, extractimagepatches_dyn) {
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i64);
EXPECT_TRUE(extractimagepatches->get_output_partial_shape(0).same_scheme(PartialShape::dynamic(4)));
EXPECT_EQ(extractimagepatches->get_output_partial_shape(0), PartialShape::dynamic(4));
}
TEST(type_prop, extractimagepatches_interval_shape_and_labels_padding_same_upper) {
auto data_shape = PartialShape{{1, 10}, {3, 4}, {10, 51}, {13, 71}};
set_shape_labels(data_shape, 10);
auto data = make_shared<op::v0::Parameter>(element::i32, data_shape);
auto sizes = Shape{1, 1};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
auto padtype_padding = op::PadType::SAME_LOWER;
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_EQ(extractimagepatches->get_output_partial_shape(0), PartialShape({{1, 10}, {3, 4}, {2, 11}, {3, 15}}));
EXPECT_THAT(get_shape_labels(extractimagepatches->get_output_partial_shape(0)), ElementsAre(10, 11, 0, 0));
}
TEST(type_prop, extractimagepatches_data_not_rank_4d) {
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
auto padtype_padding = op::PadType::VALID;
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(
make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic(3)),
sizes,
strides,
rates,
padtype_padding),
NodeValidationFailure,
HasSubstr("input tensor must be 4D tensor"));
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(
make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic(5)),
sizes,
strides,
rates,
padtype_padding),
NodeValidationFailure,
HasSubstr("input tensor must be 4D tensor"));
}
TEST(type_prop, extractimagepatches_sizes_has_no_two_elements) {
auto data = make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic());
auto sizes = Shape{3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
auto padtype_padding = op::PadType::EXPLICIT;
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding),
NodeValidationFailure,
HasSubstr("Attribute sizes should be in [size_rows, size_cols] format"));
}
TEST(type_prop, extractimagepatches_strides_has_no_two_elements) {
auto data = make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic());
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5, 1};
auto rates = Shape{1, 1};
auto padtype_padding = op::PadType::EXPLICIT;
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding),
NodeValidationFailure,
HasSubstr("Attribute strides should be in [stride_rows, stride_cols] format"));
}
TEST(type_prop, extractimagepatches_strides_has_zero_value) {
auto data = make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic());
auto sizes = Shape{3, 3};
auto strides = Strides{5, 0};
auto rates = Shape{1, 1};
auto padtype_padding = op::PadType::EXPLICIT;
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding),
NodeValidationFailure,
HasSubstr("Attribute strides should be strictly greater than zeros in values"));
}
TEST(type_prop, extractimagepatches_rates_has_no_two_elements) {
auto data = make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic());
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1};
auto padtype_padding = op::PadType::EXPLICIT;
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding),
NodeValidationFailure,
HasSubstr("Attribute rates should be in [rate_rows, rate_cols] format"));
}
TEST(type_prop, extractimagepatches_rates_has_zero_value) {
auto data = make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic());
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{0, 1};
auto padtype_padding = op::PadType::EXPLICIT;
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding),
NodeValidationFailure,
HasSubstr("Attribute rates should be strictly greater than zeros in values"));
}
TEST(type_prop, extractimagepatches_not_supported_padding) {
auto data = make_shared<op::v0::Parameter>(element::i64, PartialShape::dynamic());
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
auto padtype_padding = op::PadType::EXPLICIT;
OV_EXPECT_THROW(ignore = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padtype_padding),
NodeValidationFailure,
HasSubstr("Attribute padding should be in either valid or same_lower or same_upper"));
}
using ExtractImagesPatchesParams = std::tuple<op::PadType,
size_t, // size
size_t, // rate
size_t // stride
>;
class ExtractImagesPatchesV3Test : public TypePropOpTest<op::v3::ExtractImagePatches>,
public WithParamInterface<ExtractImagesPatchesParams> {
protected:
void SetUp() override {
const auto& p = GetParam();
pad_type = std::get<0>(p);
sizes = Shape(2, std::get<1>(p));
rates = Shape(2, std::get<2>(p));
strides = Shape(2, std::get<3>(p));
}
int64_t calc_shape_padding(const int64_t input,
const int64_t rate,
const int64_t stride,
const int64_t patch_size,
const op::PadType type) {
int64_t out = 0;
if (type == op::PadType::VALID) {
out = (input - rate * (patch_size - 1) - 1) / stride + 1;
} else {
out = 1 + (input - 1) / stride;
}
return out < 0 ? 0 : out;
}
PartialShape exp_shape() {
auto shape = PartialShape{dim0, dim1, -1, -1};
shape[1] *= sizes[0] * sizes[1];
shape[2] = calc_shape_padding(100,
static_cast<int64_t>(rates[0]),
static_cast<int64_t>(strides[0]),
static_cast<int64_t>(sizes[0]),
pad_type);
shape[3] = calc_shape_padding(100,
static_cast<int64_t>(rates[1]),
static_cast<int64_t>(strides[1]),
static_cast<int64_t>(sizes[1]),
pad_type);
return shape;
}
Shape sizes, rates;
Strides strides;
op::PadType pad_type;
int64_t dim0 = 64, dim1 = 2;
};
INSTANTIATE_TEST_SUITE_P(type_prop,
ExtractImagesPatchesV3Test,
Combine(Values(op::PadType::VALID, op::PadType::SAME_LOWER),
Range<size_t>(1, 11),
Range<size_t>(1, 11),
Range<size_t>(1, 11)),
PrintToStringParamName());
TEST_P(ExtractImagesPatchesV3Test, check_calc_padding) {
auto data = make_shared<op::v0::Parameter>(element::i32, PartialShape{dim0, dim1, 100, 100});
auto extractimagepatches = make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, pad_type);
EXPECT_EQ(extractimagepatches->get_output_element_type(0), element::i32);
EXPECT_EQ(extractimagepatches->get_output_partial_shape(0), exp_shape());
}
@@ -1,25 +0,0 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include "utils.hpp"
using namespace ov;
using namespace ov::intel_cpu;
TEST(StaticShapeInferenceTest, ExtractImagePatchesTest) {
auto data = std::make_shared<op::v0::Parameter>(element::i32, PartialShape{-1, -1, -1, -1});
auto sizes = Shape{3, 3};
auto strides = Strides{5, 5};
auto rates = Shape{1, 1};
auto padTypePadding = op::PadType::VALID;
auto extractImagePatches =
std::make_shared<op::v3::ExtractImagePatches>(data, sizes, strides, rates, padTypePadding);
// Test StaticShape
std::vector<StaticShape> static_input_shapes = {StaticShape{64, 3, 10, 10}}, static_output_shapes = {StaticShape{}};
shape_inference(extractImagePatches.get(), static_input_shapes, static_output_shapes);
ASSERT_EQ(static_output_shapes[0], (StaticShape{64, 27, 2, 2}));
}
@@ -0,0 +1,63 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include "common_test_utils/test_assertions.hpp"
#include "extract_image_patches_shape_inference.hpp"
#include "utils.hpp"
using namespace ov;
using namespace ov::intel_cpu;
using namespace testing;
class StaticShapeExtractImagePatchesV3Test : public OpStaticShapeInferenceTest<op::v3::ExtractImagePatches> {};
TEST_F(StaticShapeExtractImagePatchesV3Test, default_ctor_no_args) {
auto pad_type = op::PadType::VALID;
op = make_op();
op->set_sizes({3, 3});
op->set_strides({5, 5});
op->set_rates({1, 1});
op->set_auto_pad(pad_type);
input_shapes = ShapeVector{{10, 8, 12, 6}};
shape_inference(op.get(), input_shapes, output_shapes);
EXPECT_EQ(output_shapes.size(), 1);
EXPECT_EQ(output_shapes.front(), StaticShape({10, 72, 2, 1}));
}
TEST_F(StaticShapeExtractImagePatchesV3Test, data_input_is_dynamic_rank) {
const auto data = std::make_shared<op::v0::Parameter>(element::f32, ov::PartialShape::dynamic());
op = make_op(data, ov::Shape{3, 3}, ov::Strides{5, 5}, ov::Shape{2, 2}, op::PadType::VALID);
input_shapes = ShapeVector{{2, 2, 23, 24}};
shape_inference(op.get(), input_shapes, output_shapes);
EXPECT_EQ(output_shapes.size(), 1);
EXPECT_EQ(output_shapes.front(), StaticShape({2, 18, 4, 4}));
}
TEST_F(StaticShapeExtractImagePatchesV3Test, data_input_is_static_rank) {
const auto data = std::make_shared<op::v0::Parameter>(element::f32, ov::PartialShape::dynamic(4));
op = make_op(data, ov::Shape{3, 3}, ov::Strides{5, 5}, ov::Shape{1, 1}, op::PadType::SAME_UPPER);
input_shapes = ShapeVector{{2, 2, 43, 34}};
shape_inference(op.get(), input_shapes, output_shapes);
EXPECT_EQ(output_shapes.size(), 1);
EXPECT_EQ(output_shapes.front(), StaticShape({2, 18, 9, 7}));
}
TEST_F(StaticShapeExtractImagePatchesV3Test, data_shape_not_compatible_rank_4) {
const auto data = std::make_shared<op::v0::Parameter>(element::f32, ov::PartialShape::dynamic(4));
op = make_op(data, ov::Shape{3, 3}, ov::Strides{5, 5}, ov::Shape{1, 1}, op::PadType::SAME_UPPER);
OV_EXPECT_THROW(shape_inference(op.get(), ShapeVector{{2, 20, 12, 24, 1}}, output_shapes),
NodeValidationFailure,
HasSubstr("input tensor must be 4D tensor"));
}