Gather: removed indices normalization pass and added some checks for Gather-8 -> Gather-7 conversion (#19666)

* Do not normalize negative indices for Gather v8

* code style fix

* added transformation test with accuracy check for Gather-v8

* removed GatherNegativeConstIndicesNormalize transformation at all

* ConvertGather8ToGather7 conversion: added more checks

* Introduced shared Gather8withIndicesDataLayerTest: added CPU, GPU instances

* code style fix

* small fix

* review fixes

* do negative indices normalization if possible

* code style fix

* refactor cpu test instances

* code style fix
This commit is contained in:
Anton Voronov 2023-10-10 11:17:33 +04:00 committed by Alexander Nesterov
parent 001e114d64
commit f76b6d661c
15 changed files with 352 additions and 375 deletions

View File

@ -1,29 +0,0 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/pass/graph_rewrite.hpp"
#include "transformations_visibility.hpp"
namespace ov {
namespace pass {
class TRANSFORMATIONS_API GatherNegativeConstIndicesNormalize;
} // namespace pass
} // namespace ov
/**
* @ingroup ie_transformation_common_api
* @brief GatherNegativeConstIndicesNormalize checks if indices value is negative scalar and
* normalizes it using ShapeOf->Add->Cast subgraph.
* We need to remove this transformation after adding support of negative indices in
* future version of Gather operation.
*/
class ov::pass::GatherNegativeConstIndicesNormalize : public ov::pass::MatcherPass {
public:
OPENVINO_RTTI("GatherNegativeConstIndicesNormalize", "0");
GatherNegativeConstIndicesNormalize();
};

View File

@ -97,7 +97,6 @@
#include "transformations/op_conversions/detection_output_upgrade.hpp"
#include "transformations/op_conversions/einsum_decomposition.hpp"
#include "transformations/op_conversions/eye_decomposition.hpp"
#include "transformations/op_conversions/gather_normalize_negative_indices.hpp"
#include "transformations/op_conversions/gelu7_downgrade.hpp"
#include "transformations/op_conversions/group_normalization_decomposition.hpp"
#include "transformations/op_conversions/hsigmoid_decomposition.hpp"
@ -170,7 +169,6 @@ bool ov::pass::CommonOptimizations::run_on_model(const std::shared_ptr<ov::Model
ADD_MATCHER(decomp, EinsumDecomposition)
decomp->add_matcher<SoftmaxDecomposition, false>();
ADD_MATCHER(decomp, SoftSignDecomposition)
ADD_MATCHER(decomp, GatherNegativeConstIndicesNormalize)
ADD_MATCHER(decomp, DropoutWithRandomUniformReplacer)
ADD_MATCHER(decomp, TransposeReshapeEliminationForMatmul)
ADD_MATCHER(decomp, EyeDecomposition)

View File

@ -48,8 +48,59 @@ pass::ConvertGather8ToGather7::ConvertGather8ToGather7() {
if (!gather_v8_node)
return false;
auto data = gather_v8_node->input_value(0);
auto indices_constant =
std::dynamic_pointer_cast<ov::op::v0::Constant>(gather_v8_node->input_value(1).get_node_shared_ptr());
auto axis_constant =
std::dynamic_pointer_cast<ov::op::v0::Constant>(gather_v8_node->input_value(2).get_node_shared_ptr());
if (!indices_constant || !axis_constant)
return false;
auto axis = axis_constant->cast_vector<int64_t>();
if (axis.size() != 1) {
return false;
}
auto axis_value = axis[0];
// normalize `axis` value if it is negative
if (axis_value < 0) {
if (!data.get_partial_shape().rank().is_static()) {
return false;
}
axis_value = axis_value + data.get_partial_shape().rank().get_length();
}
if (data.get_partial_shape().rank().get_length() < axis_value) {
return false;
}
// check `axis` dimension of data tensor is static
if (!data.get_partial_shape()[axis_value].is_static()) {
return false;
}
auto axis_dim = data.get_partial_shape()[axis_value].get_length();
auto indices = indices_constant->cast_vector<int64_t>();
// Check all the indices are not out of bound and check whether normalization is possible for negative values
bool do_indices_normalization = false;
for (size_t i = 0; i < indices.size(); i++) {
if (indices[i] < -axis_dim || indices[i] >= axis_dim) {
return false;
}
if (indices[i] < 0) {
do_indices_normalization = true;
indices[i] = indices[i] + axis_dim;
}
}
std::shared_ptr<ov::Node> new_indices_constant;
if (do_indices_normalization) {
new_indices_constant = std::make_shared<ov::op::v0::Constant>(indices_constant->get_element_type(),
indices_constant->get_shape(),
indices);
} else {
new_indices_constant = indices_constant;
}
auto gather_v7_node = make_shared<ov::op::v7::Gather>(gather_v8_node->input_value(0),
gather_v8_node->input_value(1),
new_indices_constant,
gather_v8_node->input_value(2),
gather_v8_node->get_batch_dims());

View File

@ -1,86 +0,0 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "transformations/op_conversions/gather_normalize_negative_indices.hpp"
#include <memory>
#include "itt.hpp"
#include "openvino/core/rt_info.hpp"
#include "openvino/core/validation_util.hpp"
#include "openvino/op/add.hpp"
#include "openvino/op/constant.hpp"
#include "openvino/op/gather.hpp"
#include "openvino/op/shape_of.hpp"
#include "openvino/pass/pattern/op/wrap_type.hpp"
ov::pass::GatherNegativeConstIndicesNormalize::GatherNegativeConstIndicesNormalize() {
MATCHER_SCOPE(GatherNegativeConstIndicesNormalize);
auto data_input = pattern::any_input(pattern::has_static_rank());
auto axis_input = ov::pass::pattern::wrap_type<ov::op::v0::Constant>();
auto indices_input = ov::pass::pattern::wrap_type<ov::op::v0::Constant>();
auto gather_node = ov::pass::pattern::wrap_type<op::util::GatherBase>({data_input, indices_input, axis_input});
matcher_pass_callback callback = [=](ov::pass::pattern::Matcher& m) {
auto& pattern_to_output = m.get_pattern_value_map();
auto gather = pattern_to_output.at(gather_node).get_node_shared_ptr();
auto data = pattern_to_output.at(data_input);
auto axis_constant =
std::dynamic_pointer_cast<ov::op::v0::Constant>(pattern_to_output.at(axis_input).get_node_shared_ptr());
auto indices_constant =
std::dynamic_pointer_cast<ov::op::v0::Constant>(pattern_to_output.at(indices_input).get_node_shared_ptr());
if (!gather || !axis_constant || !indices_constant) {
return false;
}
auto indices = indices_constant->cast_vector<int64_t>();
if (indices.size() != 1 || indices[0] >= 0) {
return false;
}
auto axis = axis_constant->cast_vector<int64_t>();
if (axis.size() != 1) {
return false;
}
auto axis_value = axis[0];
// normalize `axis` value if it is negative
if (axis_value < 0) {
axis_value = axis_value + data.get_partial_shape().rank().get_length();
}
if (data.get_partial_shape().rank().get_length() < axis_value) {
return false;
}
// check `axis` dimension of data tensor is static
if (!data.get_partial_shape()[axis_value].is_static()) {
return false;
}
auto input_type = indices_constant->get_element_type();
auto shape_of = std::make_shared<ov::op::v3::ShapeOf>(data, input_type);
auto input_gather =
std::make_shared<ov::op::v7::Gather>(shape_of,
ov::op::v0::Constant::create(input_type, Shape{}, {axis_value}),
ov::op::v0::Constant::create(input_type, Shape{}, {0}));
std::shared_ptr<Node> add = std::make_shared<ov::op::v1::Add>(input_gather, indices_constant);
OPENVINO_SUPPRESS_DEPRECATED_START
if (auto folded_const = ov::get_constant_from_source(add)) {
OPENVINO_SUPPRESS_DEPRECATED_END
add = folded_const;
}
gather->input(1).replace_source_output(add);
ov::copy_runtime_info(gather, {shape_of, input_gather, add});
return true;
};
auto m = std::make_shared<ov::pass::pattern::Matcher>(gather_node, matcher_name);
register_matcher(m, callback);
}

View File

@ -55,7 +55,7 @@ TEST_F(TransformationTestsF, ConvertGather7toGather1_nonzero_batch_dims) {
}
}
TEST_F(TransformationTestsF, ConvertGather8toGather7) {
TEST_F(TransformationTestsF, ConvertGather8toGather7_param_indices) {
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = std::make_shared<opset1::Parameter>(element::i32, Shape{2, 2});
@ -68,15 +68,98 @@ TEST_F(TransformationTestsF, ConvertGather8toGather7) {
manager.register_pass<ov::pass::ConvertGather8ToGather7>();
}
}
TEST_F(TransformationTestsF, ConvertGather8toGather7_const_indices) {
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = opset8::Constant::create(element::i32, Shape{2, 2}, {0, 1, 2, 0});
auto axis = opset1::Constant::create(element::i32, Shape{1}, {1});
int64_t batch_dims = 1;
auto gather_v8 = std::make_shared<opset8::Gather>(data, indices, axis, batch_dims);
model = std::make_shared<ov::Model>(NodeVector{gather_v8}, ParameterVector{data});
manager.register_pass<ov::pass::ConvertGather8ToGather7>();
}
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = std::make_shared<opset1::Parameter>(element::i32, Shape{2, 2});
auto indices = opset8::Constant::create(element::i32, Shape{2, 2}, {0, 1, 2, 0});
auto axis = opset1::Constant::create(element::i32, Shape{1}, {1});
int64_t batch_dims = 1;
auto gather_v7 = std::make_shared<opset7::Gather>(data, indices, axis, batch_dims);
model_ref = std::make_shared<ov::Model>(NodeVector{gather_v7}, ParameterVector{data, indices});
model_ref = std::make_shared<ov::Model>(NodeVector{gather_v7}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, ConvertGather8toGather7_negative_indices) {
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = opset8::Constant::create(element::i32, Shape{2, 2}, {2, 1, 0, -1});
auto axis = opset1::Constant::create(element::i32, Shape{1}, {1});
int64_t batch_dims = 1;
auto gather_v8 = std::make_shared<opset8::Gather>(data, indices, axis, batch_dims);
model = std::make_shared<ov::Model>(NodeVector{gather_v8}, ParameterVector{data});
manager.register_pass<ov::pass::ConvertGather8ToGather7>();
comparator.enable(FunctionsComparator::CONST_VALUES);
}
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = opset8::Constant::create(element::i32, Shape{2, 2}, {2, 1, 0, 2});
auto axis = opset1::Constant::create(element::i32, Shape{1}, {1});
int64_t batch_dims = 1;
auto gather_v7 = std::make_shared<opset7::Gather>(data, indices, axis, batch_dims);
model_ref = std::make_shared<ov::Model>(NodeVector{gather_v7}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, ConvertGather8toGather7_out_of_bound_indices) {
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = opset8::Constant::create(element::i32, Shape{2, 2}, {0, 1, 2, 3});
auto axis = opset1::Constant::create(element::i32, Shape{1}, {1});
int64_t batch_dims = 1;
auto gather_v8 = std::make_shared<opset8::Gather>(data, indices, axis, batch_dims);
model = std::make_shared<ov::Model>(NodeVector{gather_v8}, ParameterVector{data});
manager.register_pass<ov::pass::ConvertGather8ToGather7>();
}
}
TEST_F(TransformationTestsF, ConvertGather8toGather7_negative_axis) {
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = opset8::Constant::create(element::i32, Shape{2, 2}, {0, 1, 2, 0});
auto axis = opset1::Constant::create(element::i32, Shape{1}, {-1});
int64_t batch_dims = 1;
auto gather_v8 = std::make_shared<opset8::Gather>(data, indices, axis, batch_dims);
model = std::make_shared<ov::Model>(NodeVector{gather_v8}, ParameterVector{data});
manager.register_pass<ov::pass::ConvertGather8ToGather7>();
}
{
auto data = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 3});
auto indices = opset8::Constant::create(element::i32, Shape{2, 2}, {0, 1, 2, 0});
auto axis = opset1::Constant::create(element::i32, Shape{1}, {-1});
int64_t batch_dims = 1;
auto gather_v7 = std::make_shared<opset7::Gather>(data, indices, axis, batch_dims);
model_ref = std::make_shared<ov::Model>(NodeVector{gather_v7}, ParameterVector{data});
}
}

View File

@ -1,252 +0,0 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "transformations/op_conversions/gather_normalize_negative_indices.hpp"
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include "common_test_utils/ov_test_utils.hpp"
#include "openvino/core/model.hpp"
#include "openvino/core/validation_util.hpp"
#include "openvino/opsets/opset7.hpp"
#include "openvino/pass/manager.hpp"
#include "transformations/init_node_info.hpp"
using namespace ov;
using namespace testing;
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{1, 15, 128});
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {1});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto indices_type = element::i32;
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{1, 15, 128});
auto indices = opset7::Constant::create(indices_type, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {1});
auto shape_of = std::make_shared<opset7::ShapeOf>(data, indices_type);
auto input_gather = std::make_shared<opset7::Gather>(shape_of,
opset7::Constant::create(indices_type, Shape{}, {1}),
opset7::Constant::create(indices_type, Shape{}, {0}));
auto add = std::make_shared<opset7::Add>(input_gather, indices);
OPENVINO_SUPPRESS_DEPRECATED_START
auto const_add = get_constant_from_source(add);
OPENVINO_SUPPRESS_DEPRECATED_END
if (const_add == nullptr)
OPENVINO_THROW("indices should've been constant folded");
auto gather = std::make_shared<opset7::Gather>(data, const_add, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize_neg_axis) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{1, 15, 128});
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {-2});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto indices_type = element::i32;
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{1, 15, 128});
auto indices = opset7::Constant::create(indices_type, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {-2});
auto shape_of = std::make_shared<opset7::ShapeOf>(data, indices_type);
auto input_gather = std::make_shared<opset7::Gather>(shape_of,
opset7::Constant::create(indices_type, Shape{}, {1}),
opset7::Constant::create(indices_type, Shape{}, {0}));
auto add = std::make_shared<opset7::Add>(input_gather, indices);
OPENVINO_SUPPRESS_DEPRECATED_START
auto const_add = get_constant_from_source(add);
OPENVINO_SUPPRESS_DEPRECATED_END
if (const_add == nullptr)
OPENVINO_THROW("indices should've been constant folded");
auto gather = std::make_shared<opset7::Gather>(data, const_add, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize_dif_input_types) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{1, 15, 128});
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i64, Shape{}, {1});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto indices_type = element::i32;
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{1, 15, 128});
auto indices = opset7::Constant::create(indices_type, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i64, Shape{}, {1});
auto shape_of = std::make_shared<opset7::ShapeOf>(data, indices_type);
auto input_gather = std::make_shared<opset7::Gather>(shape_of,
opset7::Constant::create(indices_type, Shape{}, {1}),
opset7::Constant::create(indices_type, Shape{}, {0}));
auto add = std::make_shared<opset7::Add>(input_gather, indices);
OPENVINO_SUPPRESS_DEPRECATED_START
auto const_add = get_constant_from_source(add);
OPENVINO_SUPPRESS_DEPRECATED_END
if (const_add == nullptr)
OPENVINO_THROW("indices should've been constant folded");
auto gather = std::make_shared<opset7::Gather>(data, const_add, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize_static_axis_dim) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape{DYN, 15, DYN});
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {1});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto indices_type = element::i32;
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape{DYN, 15, DYN});
auto indices = opset7::Constant::create(indices_type, Shape{}, {2});
auto axis = opset7::Constant::create(element::i32, Shape{}, {1});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize_static_axis_dim_neg_axis) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape{DYN, 15, DYN});
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {-2});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto indices_type = element::i32;
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape{DYN, 15, DYN});
auto indices = opset7::Constant::create(indices_type, Shape{}, {2});
auto axis = opset7::Constant::create(element::i32, Shape{}, {-2});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize_non_static_axis_dim) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape{DYN, DYN, DYN});
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {1});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto indices_type = element::i32;
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape{DYN, DYN, DYN});
auto indices = opset7::Constant::create(indices_type, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {1});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize_positive_ind) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{2, 3});
auto indices = opset7::Constant::create(element::i32, Shape{}, {1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {0});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto data = std::make_shared<opset7::Parameter>(element::f32, Shape{2, 3});
auto indices = opset7::Constant::create(element::i32, Shape{}, {1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {0});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}
TEST_F(TransformationTestsF, GatherNegativeIndicesNormalize_non_static_rank) {
{
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape::dynamic(Rank::dynamic()));
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {0});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis, 0);
model = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
manager.register_pass<ov::pass::GatherNegativeConstIndicesNormalize>();
}
{
auto data = std::make_shared<opset7::Parameter>(element::f32, PartialShape::dynamic());
auto indices = opset7::Constant::create(element::i32, Shape{}, {-1});
auto axis = opset7::Constant::create(element::i32, Shape{}, {0});
auto gather = std::make_shared<opset7::Gather>(data, indices, axis);
model_ref = std::make_shared<ov::Model>(NodeVector{gather}, ParameterVector{data});
}
}

View File

@ -9,6 +9,7 @@
namespace {
using ov::test::Gather7LayerTest;
using ov::test::Gather8LayerTest;
using ov::test::Gather8withIndicesDataLayerTest;
const std::vector<ov::element::Type> model_types = {
ov::element::f32,
@ -203,4 +204,29 @@ const auto gatherParamsVec3 = testing::Combine(
INSTANTIATE_TEST_CASE_P(smoke_Vec3, Gather8LayerTest, gatherParamsVec3, Gather8LayerTest::getTestCaseName);
const ov::test::gather7ParamsTuple dummyParams = {
ov::test::static_shapes_to_test_representation(std::vector<ov::Shape>{{2, 3}}), // input shape
ov::Shape{2, 2}, // indices shape
std::tuple<int, int>{1, 1}, // axis, batch
ov::element::f32, // model type
ov::test::utils::DEVICE_CPU // device
};
const std::vector<std::vector<int64_t>> indicesData = {
{0, 1, 2, 0}, // positive in bound
{-1, -2, -3, -1}, // negative in bound
{-1, 0, 1, 2}, // positive and negative in bound
{0, 1, 2, 3}, // positive out of bound
{-1, -2, -3, -4}, // negative out of bound
{0, 4, -4, 0}, // positive and negative out of bound
};
const auto gatherWithIndicesParams = testing::Combine(
testing::Values(dummyParams),
testing::ValuesIn(indicesData)
);
INSTANTIATE_TEST_CASE_P(smoke, Gather8withIndicesDataLayerTest, gatherWithIndicesParams, Gather8withIndicesDataLayerTest::getTestCaseName);
} // namespace

View File

@ -177,8 +177,6 @@ std::vector<std::string> disabledTestPatterns() {
R"(.*(Hetero).*InferRequestPreprocessTest.*SetPreProcessToInferRequest.*)",
// TODO: for 22.2 (Issue 68949)
R"(.*smoke_AutoBatching_CPU/AutoBatching_Test_DetectionOutput.*)",
// Issue: 117837
R"(.*smoke_4D_out_of_range/GatherInPlaceLayerTestCPU.*_indices=\(\-15\).*)",
// Issue: 120222
R"(.*smoke_TopK/TopKLayerTest.Inference.*_k=1_axis=3_.*_modelType=f16_trgDev=CPU.*)",
R"(.*smoke_TopK/TopKLayerTest.Inference.*_k=7_axis=3_.*_modelType=f16_trgDev=CPU.*)",

View File

@ -578,4 +578,32 @@ INSTANTIATE_TEST_SUITE_P(
Gather8IndiceScalarLayerTest::getTestCaseName
);
gather7ParamsTuple dummyParams = {
std::vector<size_t>{2, 3},
std::vector<size_t>{2, 2},
std::tuple<int, int>{1, 1},
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::UNSPECIFIED,
InferenceEngine::Precision::UNSPECIFIED,
InferenceEngine::Layout::ANY,
InferenceEngine::Layout::ANY,
ov::test::utils::DEVICE_GPU,
};
std::vector<std::vector<int>> indicesData = {
{0, 1, 2, 0}, // positive in bound
{-1, -2, -3, -1}, // negative in bound
{-1, 0, 1, 2}, // positive and negative in bound
{0, 1, 2, 3}, // positive out of bound
{-1, -2, -3, -4}, // negative out of bound
{0, 4, -4, 0}, // positive and negative out of bound
};
const auto gatherWithIndicesParams = testing::Combine(
testing::Values(dummyParams),
testing::ValuesIn(indicesData)
);
INSTANTIATE_TEST_CASE_P(smoke, Gather8withIndicesDataLayerTest, gatherWithIndicesParams, Gather8withIndicesDataLayerTest::getTestCaseName);
} // namespace

View File

@ -24,4 +24,8 @@ TEST_P(Gather8IndiceScalarLayerTest, CompareWithRefs) {
Run();
};
TEST_P(Gather8withIndicesDataLayerTest, CompareWithRefs) {
Run();
};
} // namespace LayerTestsDefinitions

View File

@ -23,5 +23,9 @@ TEST_P(Gather8LayerTest, Inference) {
TEST_P(Gather8IndiceScalarLayerTest, Inference) {
run();
};
TEST_P(Gather8withIndicesDataLayerTest, Inference) {
run();
};
} // namespace test
} // namespace ov

View File

@ -83,4 +83,18 @@ protected:
void SetUp() override;
};
typedef std::tuple<
gather7ParamsTuple,
std::vector<int> // indices data
> gather8withIndicesDataParamsTuple;
class Gather8withIndicesDataLayerTest : public testing::WithParamInterface<gather8withIndicesDataParamsTuple>,
virtual public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(const testing::TestParamInfo<gather8withIndicesDataParamsTuple>& obj);
protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions

View File

@ -63,5 +63,20 @@ public:
protected:
void SetUp() override;
};
typedef std::tuple<
gather7ParamsTuple,
std::vector<int64_t> // indices data
> gather8withIndicesDataParamsTuple;
class Gather8withIndicesDataLayerTest : public testing::WithParamInterface<gather8withIndicesDataParamsTuple>,
virtual public ov::test::SubgraphBaseTest {
public:
static std::string getTestCaseName(const testing::TestParamInfo<gather8withIndicesDataParamsTuple>& obj);
protected:
void SetUp() override;
};
} // namespace test
} // namespace ov

View File

@ -178,4 +178,56 @@ void Gather8IndiceScalarLayerTest::SetUp() {
function = std::make_shared<ngraph::Function>(results, functionParams, "gather");
}
std::string Gather8withIndicesDataLayerTest::getTestCaseName(const testing::TestParamInfo<gather8withIndicesDataParamsTuple>& obj) {
gather7ParamsTuple basicParams;
std::vector<int> indicesData;
std::tie(basicParams, indicesData) = obj.param;
std::tuple<int, int> axis_batchIdx;
std::vector<int> indices;
std::vector<size_t> indicesShape, inputShape;
InferenceEngine::Precision netPrecision;
InferenceEngine::Precision inPrc, outPrc;
InferenceEngine::Layout inLayout, outLayout;
std::string targetName;
std::tie(inputShape, indicesShape, axis_batchIdx, netPrecision, inPrc, outPrc, inLayout, outLayout, targetName) = basicParams;
std::ostringstream result;
result << "IS=" << ov::test::utils::vec2str(inputShape) << "_";
result << "indicesShape=" << ov::test::utils::vec2str(indicesShape) << "_";
result << "axis=" << std::get<0>(axis_batchIdx) << "_";
result << "batchIdx=" << std::get<1>(axis_batchIdx) << "_";
result << "netPRC=" << netPrecision.name() << "_";
result << "inPRC=" << inPrc.name() << "_";
result << "outPRC=" << outPrc.name() << "_";
result << "inL=" << inLayout << "_";
result << "outL=" << outLayout << "_";
result << "trgDev=" << targetName << "_";
result << "indicesData=" << ov::test::utils::vec2str(indicesData) << "_";
return result.str();
}
void Gather8withIndicesDataLayerTest::SetUp() {
gather7ParamsTuple basicParams;
std::vector<int> indicesData;
std::tie(basicParams, indicesData) = GetParam();
std::tuple<int, int> axis_batchIdx;
std::vector<size_t> indicesShape;
std::vector<size_t> inputShape;
InferenceEngine::Precision netPrecision;
std::tie(inputShape, indicesShape, axis_batchIdx, netPrecision, inPrc, outPrc, inLayout, outLayout, targetDevice) = basicParams;
int axis = std::get<0>(axis_batchIdx);
int batchIdx = std::get<1>(axis_batchIdx);
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
ov::ParameterVector functionParams {std::make_shared<ov::op::v0::Parameter>(ngPrc, ov::Shape(inputShape))};
auto paramOuts = ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes<ngraph::op::Parameter>(functionParams));
auto indicesNode = ngraph::builder::makeConstant<int>(ngraph::element::i64, indicesShape, indicesData);
auto axisNode = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape({}), { axis });
auto gather = std::make_shared<ngraph::opset8::Gather>(paramOuts[0], indicesNode, axisNode, batchIdx);
ngraph::ResultVector results{ std::make_shared<ngraph::opset8::Result>(gather) };
function = std::make_shared<ngraph::Function>(results, functionParams, "gather");
}
} // namespace LayerTestsDefinitions

View File

@ -167,5 +167,76 @@ void Gather8IndiceScalarLayerTest::SetUp() {
auto result = std::make_shared<ov::op::v0::Result>(gather);
function = std::make_shared<ov::Model>(result, ov::ParameterVector{param}, "gather");
}
std::string Gather8withIndicesDataLayerTest::getTestCaseName(const testing::TestParamInfo<gather8withIndicesDataParamsTuple>& obj) {
gather7ParamsTuple basicParams;
std::vector<int64_t> indicesData;
std::tie(basicParams, indicesData) = obj.param;
std::tuple<int, int> axis_batch_idx;
std::vector<int> indices;
ov::Shape indices_shape;
std::vector<InputShape> shapes;
ov::element::Type model_type;
std::string device_name;
std::tie(shapes, indices_shape, axis_batch_idx, model_type, device_name) = basicParams;
std::ostringstream result;
result << "IS=(";
for (size_t i = 0lu; i < shapes.size(); i++) {
result << ov::test::utils::partialShape2str({shapes[i].first}) << (i < shapes.size() - 1lu ? "_" : "");
}
result << ")_TS=";
for (size_t i = 0lu; i < shapes.front().second.size(); i++) {
result << "{";
for (size_t j = 0lu; j < shapes.size(); j++) {
result << ov::test::utils::vec2str(shapes[j].second[i]) << (j < shapes.size() - 1lu ? "_" : "");
}
result << "}_";
}
result << "axis=" << std::get<0>(axis_batch_idx) << "_";
result << "batch_idx=" << std::get<1>(axis_batch_idx) << "_";
result << "indices_shape=" << ov::test::utils::vec2str(indices_shape) << "_";
result << "netPRC=" << model_type.get_type_name() << "_";
result << "trgDev=" << device_name << "_";
result << "indicesData=" << ov::test::utils::vec2str(indicesData) << "_";
return result.str();
}
void Gather8withIndicesDataLayerTest::SetUp() {
gather7ParamsTuple basicParams;
std::vector<int64_t> indicesData;
std::tie(basicParams, indicesData) = GetParam();
std::tuple<int, int> axis_batch_idx;
ov::Shape indices_shape;
std::vector<InputShape> shapes;
ov::element::Type model_type;
std::tie(shapes, indices_shape, axis_batch_idx, model_type, targetDevice) = basicParams;
init_input_shapes(shapes);
int axis = std::get<0>(axis_batch_idx);
int batch_idx = std::get<1>(axis_batch_idx);
auto param = std::make_shared<ov::op::v0::Parameter>(model_type, inputDynamicShapes.front());
// create indices tensor and fill data
ov::Tensor indices_node_tensor{ov::element::i64, indices_shape};
auto indices_tensor_data = indices_node_tensor.data<int64_t>();
for (size_t i = 0; i < shape_size(indices_shape); i++) {
indices_tensor_data[i] = indicesData[i];
}
auto indices_node = std::make_shared<ov::op::v0::Constant>(indices_node_tensor);
auto axis_node = ov::op::v0::Constant::create(ov::element::i64, ov::Shape(), {axis});
auto gather = std::make_shared<ov::op::v8::Gather>(param, indices_node, axis_node, batch_idx);
auto result = std::make_shared<ov::op::v0::Result>(gather);
function = std::make_shared<ov::Model>(result, ov::ParameterVector{param}, "gather");
}
} // namespace test
} // namespace ov