[nGraph] Gather 7 evaluate (#5088)

* initial working solution

* constant_folding for Gather-7 successfully enabled

* successfuuly added remaining unittests

* removed redundant evaluate from private

* fixed evaluate for dynamic axis

* fix pre-commit for KMB: added default batch_dims=0 to runtime/reference

* clang_format_fix

* added include ngraph/shape.hpp to fix compilation for onednn-plugin

* temporary removed out of bound check for gather

* removed optional argument for batch_dims

* added const

* finally successfully run on ARM: removed redundant declaration

* style fix

* changed argument types from size_t -> int64_t

* changed back to size_t
This commit is contained in:
Pavel Esir 2021-04-12 17:01:39 +03:00 committed by GitHub
parent 1662ee0647
commit 6d2740a335
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1204 additions and 116 deletions

View File

@ -81,6 +81,16 @@ namespace ngraph
int64_t get_axis() const;
bool is_axis_set() const;
bool evaluate_gather(const HostTensorVector& outputs,
const HostTensorVector& inputs) const;
bool evaluate(const HostTensorVector& outputs,
const HostTensorVector& inputs) const override;
bool evaluate_lower(const HostTensorVector& outputs) const override;
bool evaluate_upper(const HostTensorVector& outputs) const override;
bool constant_fold(OutputVector& output_values,
const OutputVector& inputs_values) override;
private:
int64_t m_batch_dims = 0;
};

View File

@ -6,9 +6,7 @@
#include <numeric>
#include "ngraph/coordinate_range.hpp"
#include "ngraph/coordinate_transform.hpp"
#include "ngraph/runtime/reference/gather_nd.hpp"
#include "ngraph/shape.hpp"
#include "utils/span.hpp"
namespace ngraph
@ -17,107 +15,54 @@ namespace ngraph
{
namespace reference
{
namespace
{
template <typename Container>
Shape to_shape(const Container& c)
{
return Shape(begin(c), end(c));
}
template <typename Container>
std::vector<size_t>
join(const Container& c1, const Container& c2, const Container& c3)
{
using container_value_type =
typename std::remove_cv<typename Container::value_type>::type;
static_assert(std::is_same<container_value_type, size_t>::value,
"Expect same type in container");
std::vector<size_t> ret;
ret.reserve(c1.size() + c2.size() + c3.size());
std::copy(begin(c1), end(c1), std::back_inserter(ret));
std::copy(begin(c2), end(c2), std::back_inserter(ret));
std::copy(begin(c3), end(c3), std::back_inserter(ret));
return ret;
}
const auto only_one = [] { return coordinates::index(Shape{1}); };
} // namespace
template <typename T, typename U>
void gather(const T* const params,
void gather(const T* const data,
const U* const indices,
T* const out,
const Shape& params_shape,
T* out,
const Shape& data_shape,
const Shape& indices_shape,
const Shape& out_shape,
size_t axis)
size_t axis,
size_t batch_dims = 0)
{
using std::next;
assert(std::memset(out, 0, shape_size(out_shape) * sizeof(T)));
// flattened shapes
int64_t batch_size = shape_size(span(data_shape).subspan(0, batch_dims));
int64_t outer_size =
shape_size(span(data_shape).subspan(batch_dims, axis - batch_dims));
int64_t indices_size = shape_size(span(indices_shape).subspan(batch_dims));
int64_t inner_size = shape_size(span(data_shape).subspan(axis + 1));
const auto params_axes_part = span(params_shape).subspan(0, axis);
int64_t batch_data_mul = shape_size(span(data_shape).subspan(batch_dims));
int64_t batch_out_mul = shape_size(span(out_shape).subspan(batch_dims));
int64_t batch_indices_mul = shape_size(span(indices_shape).subspan(batch_dims));
NGRAPH_CHECK(params_shape.size() >= axis, "Not enough axes in param_shape.");
int64_t axis_size = data_shape[axis];
int64_t data_offset, out_offset, idx;
const auto remainder_part_shape = span(params_shape).subspan(axis + 1);
const auto found_out_shape =
join(params_axes_part, span(indices_shape), remainder_part_shape);
NGRAPH_CHECK(found_out_shape == out_shape,
"Output shape mismatch with calculations");
const auto batch_shape = span(params_shape).subspan(axis);
const auto batch_size = shape_size(batch_shape);
const auto copy_size = shape_size(remainder_part_shape);
const size_t copy_round_in_batch =
indices_shape.size() > 1
? shape_size(span(indices_shape.data(), indices_shape.size() - 1))
: 1;
const size_t round_batch_offset = indices_shape.empty() ? 1 : indices_shape.back();
auto dst = out;
auto gather_range = params_axes_part.empty()
? only_one()
: coordinates::index(to_shape(params_axes_part));
for (auto i : gather_range)
{
auto batch_index = i.begin_index;
for (size_t batch = 0; batch != i.element_number;
batch_index += i.step, ++batch)
for (int64_t batch = 0; batch < batch_size; batch++)
for (int64_t outer_idx = 0; outer_idx < outer_size; outer_idx++)
{
const auto batch_offset = batch_index * batch_size;
assert(batch_offset < shape_size(params_shape));
for (size_t round = 0; round != copy_round_in_batch; ++round)
data_offset = batch_data_mul * batch + inner_size * axis_size * outer_idx;
out_offset = batch_out_mul * batch + indices_size * inner_size * outer_idx;
for (int64_t i = 0; i < indices_size; i++)
{
const U* input_indices = indices + round * round_batch_offset;
const auto indices_no =
indices_shape.empty() ? 1 : indices_shape.back();
idx = indices[i + batch_indices_mul * batch];
// clang-format off
// todo: check if bound check is needed
// if (idx >= axis_size || (idx < 0 && -idx >= axis_size))
// throw std::domain_error{"indices values of Gather exceed size along axis"};
// clang-format on
if (idx < 0)
idx += axis_size;
assert(!batch_shape.empty());
for (size_t ii = 0; ii != indices_no; ++ii)
{
const auto positive_input_index =
input_indices[ii] < 0 ? batch_shape.front() + input_indices[ii]
: input_indices[ii];
const auto src_offset =
batch_offset + copy_size * positive_input_index;
const auto src_begin = next(params, src_offset);
const auto src_end = next(src_begin, copy_size);
std::copy(src_begin, src_end, dst);
dst += copy_size;
}
const auto src_begin = std::next(data, data_offset + inner_size * idx);
const auto src_end = std::next(src_begin, inner_size);
const auto out_ptr = std::next(out, out_offset + inner_size * i);
std::copy(src_begin, src_end, out_ptr);
}
}
}
}
} // namespace reference
} // namespace runtime
} // namespace ngraph

View File

@ -202,8 +202,8 @@ void op::v7::Gather::validate_and_infer_types()
{
NODE_VALIDATION_CHECK(
this,
batch_dims < indices_rank.get_length(),
"The batch_dims must be < indices_rank. But instead got: batch_dims = ",
batch_dims <= indices_rank.get_length(),
"The batch_dims must be <= indices_rank. But instead got: batch_dims = ",
batch_dims,
", indices_rank = ",
indices_rank.get_length());
@ -315,18 +315,19 @@ namespace gather
bool evaluate(const HostTensorPtr& arg0,
const HostTensorPtr& arg1,
const HostTensorPtr& out,
size_t axis)
size_t axis,
size_t batch_dims)
{
using T = typename element_type_traits<ET>::value_type;
Shape params_shape = arg0->get_shape();
Shape indices_shape = arg1->get_shape();
Shape out_shape(params_shape.size() + indices_shape.size() - 1);
Shape out_shape(params_shape.size() + indices_shape.size() - 1 - batch_dims);
uint64_t i = 0;
for (; i < axis; i++)
{
out_shape[i] = params_shape[i];
}
for (uint64_t j = 0; j < indices_shape.size(); i++, j++)
for (uint64_t j = batch_dims; j < indices_shape.size(); i++, j++)
{
out_shape[i] = indices_shape[j];
}
@ -345,7 +346,8 @@ namespace gather
arg0->get_shape(),
arg1->get_shape(),
out->get_shape(),
axis);
axis,
batch_dims);
}
else if (arg1->get_element_type() == element::i32)
{
@ -355,7 +357,8 @@ namespace gather
arg0->get_shape(),
arg1->get_shape(),
out->get_shape(),
axis);
axis,
batch_dims);
}
else
{
@ -368,19 +371,20 @@ namespace gather
bool evaluate_gather(const HostTensorPtr& arg0,
const HostTensorPtr& arg1,
const HostTensorPtr& out,
size_t axis)
size_t axis,
size_t batch_dims = 0)
{
bool rc = true;
switch (out->get_element_type())
{
NGRAPH_TYPE_CASE(evaluate_gather, i32, arg0, arg1, out, axis);
NGRAPH_TYPE_CASE(evaluate_gather, i64, arg0, arg1, out, axis);
NGRAPH_TYPE_CASE(evaluate_gather, u32, arg0, arg1, out, axis);
NGRAPH_TYPE_CASE(evaluate_gather, u64, arg0, arg1, out, axis);
NGRAPH_TYPE_CASE(evaluate_gather, f16, arg0, arg1, out, axis);
NGRAPH_TYPE_CASE(evaluate_gather, f32, arg0, arg1, out, axis);
NGRAPH_TYPE_CASE(evaluate_gather, boolean, arg0, arg1, out, axis);
NGRAPH_TYPE_CASE(evaluate_gather, i32, arg0, arg1, out, axis, batch_dims);
NGRAPH_TYPE_CASE(evaluate_gather, i64, arg0, arg1, out, axis, batch_dims);
NGRAPH_TYPE_CASE(evaluate_gather, u32, arg0, arg1, out, axis, batch_dims);
NGRAPH_TYPE_CASE(evaluate_gather, u64, arg0, arg1, out, axis, batch_dims);
NGRAPH_TYPE_CASE(evaluate_gather, f16, arg0, arg1, out, axis, batch_dims);
NGRAPH_TYPE_CASE(evaluate_gather, f32, arg0, arg1, out, axis, batch_dims);
NGRAPH_TYPE_CASE(evaluate_gather, boolean, arg0, arg1, out, axis, batch_dims);
default: rc = false; break;
}
return rc;
@ -518,3 +522,63 @@ bool op::v1::Gather::constant_fold(OutputVector& output_values, const OutputVect
output_values, input_values, get_output_partial_shape(0));
}
}
bool op::v7::Gather::evaluate_gather(const HostTensorVector& outputs,
const HostTensorVector& inputs) const
{
int64_t axis = 0;
switch (inputs[2]->get_element_type())
{
case element::Type_t::i32: axis = inputs[2]->get_data_ptr<element::Type_t::i32>()[0]; break;
case element::Type_t::i64: axis = inputs[2]->get_data_ptr<element::Type_t::i64>()[0]; break;
default: throw ngraph_error("axis must be of int32 or int64 type.");
}
if (axis < 0)
{
const auto& input_rank = get_input_partial_shape(0).rank();
if (input_rank.is_static())
{
axis += input_rank.get_length();
}
}
return gather::evaluate_gather(inputs[0], inputs[1], outputs[0], axis, get_batch_dims());
}
bool op::v7::Gather::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const
{
NGRAPH_OP_SCOPE(v7_Gather_evaluate);
NGRAPH_CHECK(this, validate_host_tensor_vector(inputs, 3));
NGRAPH_CHECK(this, validate_host_tensor_vector(outputs, 1));
return evaluate_gather(outputs, inputs);
}
bool op::v7::Gather::evaluate_lower(const HostTensorVector& output_values) const
{
if (!input_value(1).get_tensor().has_and_set_bound() ||
!input_value(2).get_tensor().has_and_set_bound())
return false;
return default_lower_bound_evaluator(this, output_values);
}
bool op::v7::Gather::evaluate_upper(const HostTensorVector& output_values) const
{
if (!input_value(1).get_tensor().has_and_set_bound() ||
!input_value(2).get_tensor().has_and_set_bound())
return false;
return default_upper_bound_evaluator(this, output_values);
}
bool op::v7::Gather::constant_fold(OutputVector& output_values, const OutputVector& input_values)
{
// try the regular constant folding just for the Gather node
if (Node::constant_fold(output_values, input_values))
{
return true;
}
else
{
return gather::cf_gather_with_subgraph(
output_values, input_values, get_output_partial_shape(0));
}
}

View File

@ -450,11 +450,19 @@ NGRAPH_TEST(${BACKEND_NAME}, gather_axis_0_int32)
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v1::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
// clang-format off
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int32_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int32_t>({0, 1, 1, 2});
test_case.add_expected_output<int32_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.add_input<int32_t>({10, 11,
20, 21,
30, 31});
test_case.add_input<int32_t>({0, 1,
1, 2});
test_case.add_expected_output<int32_t>(out_shape, {10, 11,
20, 21,
20, 21,
30, 31});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
@ -548,7 +556,560 @@ NGRAPH_TEST(${BACKEND_NAME}, gather_axis_0_uint64)
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_axis_0_bool)
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_4d_indices_axis_0_uint8)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2, 3, 4};
Shape out_shape{2, 2, 3, 4, 2};
auto P = make_shared<op::Parameter>(element::u8, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<uint8_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int32_t>({0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2,
0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2,
0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2});
test_case.add_expected_output<uint8_t>(
out_shape, {10, 11, 20, 21, 20, 21, 30, 31, 10, 11, 20, 21, 20, 21, 30, 31, 10, 11, 20, 21,
20, 21, 30, 31, 10, 11, 20, 21, 20, 21, 30, 31, 10, 11, 20, 21, 20, 21, 30, 31,
10, 11, 20, 21, 20, 21, 30, 31, 10, 11, 20, 21, 20, 21, 30, 31, 10, 11, 20, 21,
20, 21, 30, 31, 10, 11, 20, 21, 20, 21, 30, 31, 10, 11, 20, 21, 20, 21, 30, 31,
10, 11, 20, 21, 20, 21, 30, 31, 10, 11, 20, 21, 20, 21, 30, 31});
test_case.run();
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_4d_indices_axis_0_2d_input)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2, 3, 4};
Shape out_shape{2, 2, 3, 4, 2};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<float>({1.0f, 1.1f,
2.0f, 2.1f,
3.0f, 3.1f});
test_case.add_input<int32_t>({0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2});
test_case.add_expected_output<float>(
out_shape,
{ 1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_3d_indices_axis_0_2d_input)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 3, 4};
Shape out_shape{2, 3, 4, 2};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<float>({1.0f, 1.1f,
2.0f, 2.1f,
3.0f, 3.1f});
test_case.add_input<int32_t>(
{0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2,
0, 1, 1, 2});
test_case.add_expected_output<float>(
out_shape, {1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f,
1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_1d_int32)
{
Shape data_shape{3};
Shape indices_shape{2};
Shape out_shape{2};
auto P = make_shared<op::Parameter>(element::i32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<int32_t>({1, 2, 3});
test_case.add_input<int32_t>({2, 0});
test_case.add_expected_output<int32_t>(out_shape, {3, 1});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_2d_indices_axis_0_2d_input)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<float>({1.0f, 1.1f,
2.0f, 2.1f,
3.0f, 3.1f});
// clang-format on
test_case.add_input<int32_t>({0, 1, 1, 2});
// clang-format off
test_case.add_expected_output<float>(out_shape,
{1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_2d_negative_and_positive_indices_axis_0_2d_input)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<float>({1.0f, 1.1f,
2.0f, 2.1f,
3.0f, 3.1f});
// clang-format on
test_case.add_input<int32_t>({0, -2, 1, 2});
// clang-format off
test_case.add_expected_output<float>(out_shape,
{1.0f, 1.1f,
2.0f, 2.1f,
2.0f, 2.1f,
3.0f, 3.1f});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_1d_indices_axis_0_1d_input)
{
Shape data_shape{3};
Shape indices_shape{2};
Shape out_shape{2};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<float>({1.0f, 2.0f, 3.0f});
test_case.add_input<int32_t>({1, 0});
test_case.add_expected_output<float>(out_shape, {2.0f, 1.0f});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_scalar_indices_axis_0_2d_input)
{
Shape data_shape{3, 2};
Shape indices_shape{};
Shape out_shape{2};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<float>({1.0f, 1.1f, 2.0f, 2.1f, 3.0f, 3.1f});
test_case.add_input<int32_t>({1});
test_case.add_expected_output<float>(out_shape, {2.0f, 2.1f});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_2d_indices_axis_1_2d_input)
{
Shape data_shape{3, 3};
Shape indices_shape{1, 2};
Shape out_shape{3, 1, 2};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {1});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<float>({1.0f, 1.1f, 1.2f,
2.0f, 2.1f, 2.2f,
3.0f, 3.1f, 3.2f});
// clang-format on
test_case.add_input<int32_t>({0, 2});
// clang-format off
test_case.add_expected_output<float>(out_shape, {1.0f, 1.2f,
2.0f, 2.2f,
3.0f, 3.2f});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_1d_indices_axis_2_4d_input)
{
Shape data_shape{2, 2, 3, 3};
Shape indices_shape{2};
Shape out_shape{2, 2, 2, 3};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {2});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<float>({ 1.0f, 1.1f, 1.2f,
2.0f, 2.1f, 2.2f,
3.0f, 3.1f, 3.2f,
11.0f, 11.1f, 11.2f,
12.0f, 12.1f, 12.2f,
13.0f, 13.1f, 13.2f,
101.0f, 101.1f, 101.2f,
102.0f, 102.1f, 102.2f,
103.0f, 103.1f, 103.2f,
111.0f, 111.1f, 111.2f,
112.0f, 112.1f, 112.2f,
113.0f, 113.1f, 113.2f});
// clang-format on
test_case.add_input<int32_t>({0, 2});
// clang-format off
test_case.add_expected_output<float>(
out_shape, { 1.0f, 1.1f, 1.2f,
3.0f, 3.1f, 3.2f,
11.0f, 11.1f, 11.2f,
13.0f, 13.1f, 13.2f,
101.0f, 101.1f, 101.2f,
103.0f, 103.1f, 103.2f,
111.0f, 111.1f, 111.2f,
113.0f, 113.1f, 113.2f});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_scalar_indices_axis_1_2d_input)
{
Shape data_shape{3, 3};
Shape indices_shape{};
Shape out_shape{3};
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {1});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<float>({1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f, 3.0f, 3.1f, 3.2f});
test_case.add_input<int32_t>({0});
test_case.add_expected_output<float>(out_shape, {1.0f, 2.0f, 3.0f});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_int8)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::i8, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int8_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int32_t>({0, 1, 1, 2});
test_case.add_expected_output<int8_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_int16)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::i16, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int16_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int64_t>({0, 1, 1, 2});
test_case.add_expected_output<int16_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_int32)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::i32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
// clang-format off
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int32_t>({10, 11,
20, 21,
30, 31});
test_case.add_input<int32_t>({0, 1,
1, 2});
test_case.add_expected_output<int32_t>(out_shape, {10, 11,
20, 21,
20, 21,
30, 31});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_int64)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::i64, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int64_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int64_t>({0, 1, 1, 2});
test_case.add_expected_output<int64_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_uint8)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::u8, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<uint8_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int32_t>({0, 1, 1, 2});
test_case.add_expected_output<uint8_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_uint16)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::u16, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<uint16_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int64_t>({0, 1, 1, 2});
test_case.add_expected_output<uint16_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_uint32)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::u32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<uint32_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int32_t>({0, 1, 1, 2});
test_case.add_expected_output<uint32_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_uint64)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
Shape out_shape{2, 2, 2};
auto P = make_shared<op::Parameter>(element::u64, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<uint64_t>({10, 11, 20, 21, 30, 31});
test_case.add_input<int64_t>({0, 1, 1, 2});
test_case.add_expected_output<uint64_t>(out_shape, {10, 11, 20, 21, 20, 21, 30, 31});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_axis_0_bool)
{
Shape data_shape{3, 2};
Shape indices_shape{2, 2};
@ -556,7 +1117,7 @@ NGRAPH_TEST(${BACKEND_NAME}, gather_axis_0_bool)
auto P = make_shared<op::Parameter>(element::boolean, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {0});
auto G = make_shared<op::v1::Gather>(P, I, A);
auto G = make_shared<op::v7::Gather>(P, I, A);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
@ -565,3 +1126,165 @@ NGRAPH_TEST(${BACKEND_NAME}, gather_axis_0_bool)
test_case.add_expected_output<char>(out_shape, {1, 1, 1, 0, 1, 0, 0, 1});
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_data_int32_3d_indices_axis_1_batch_dims_1)
{
Shape data_shape{2, 3};
Shape indices_shape{2, 2, 2};
Shape out_shape{2, 2, 2};
int64_t batch_dims = 1;
int64_t axis = 1;
auto P = make_shared<op::Parameter>(element::i32, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {axis});
auto G = make_shared<op::v7::Gather>(P, I, A, batch_dims);
auto f = make_shared<Function>(G, ParameterVector{P, I});
// clang-format off
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int32_t>({1, 2, 3, // batch 0
4, 5, 6}); // batch 1
test_case.add_input<int64_t>({0, 1, // batch 0
1, 2,
2, 0, // batch 1
1, 2});
test_case.add_expected_output<int32_t>(out_shape, {1, 2, // batch 1
2, 3,
6, 4, // batch 1
5, 6});
test_case.run();
// clang-format on
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_data_int32_2d_indices_axis_1_batch_dims_1)
{
Shape data_shape{2, 5};
Shape indices_shape{2, 3};
Shape out_shape{2, 3};
int64_t batch_dims = 1;
int64_t axis = 1;
auto P = make_shared<op::Parameter>(element::i32, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {axis});
auto G = make_shared<op::v7::Gather>(P, I, A, batch_dims);
auto f = make_shared<Function>(G, ParameterVector{P, I});
// clang-format off
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int32_t>({1, 2, 3, 4, 5, // batch 0
6, 7, 8, 9, 10}); // batch 1
test_case.add_input<int64_t>({0, 0, 4, // batch 0
4, 0, 0}); // batch 1
test_case.add_expected_output<int32_t>(out_shape, {1, 1, 5, // batch 0
10, 6, 6}); // batch 1
test_case.run();
// clang-format on
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_4d_data_axis_2_batch_dims_1_int32)
{
Shape data_shape{2, 1, 5, 4};
Shape indices_shape{2, 3};
Shape out_shape{2, 1, 3, 4};
int64_t batch_dims = 1;
int64_t axis = 2;
auto P = make_shared<op::Parameter>(element::i32, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {axis});
auto G = make_shared<op::v7::Gather>(P, I, A, batch_dims);
auto f = make_shared<Function>(G, ParameterVector{P, I});
// clang-format off
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int32_t>({
1, 2, 3, 4, // first batch
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
17, 18, 19, 20,
21, 22, 23, 24, // second batch
25, 26, 27, 28,
29, 30, 31, 32,
33, 34, 35, 36,
37, 38, 39, 40
});
test_case.add_input<int64_t>({
1, 2, 4, // first batch
4, 3, 2 // second batch
});
test_case.add_expected_output<int32_t>(out_shape, {
5, 6, 7, 8,
9, 10, 11, 12,
17, 18, 19, 20,
37, 38, 39, 40,
33, 34, 35, 36,
29, 30, 31, 32
});
test_case.run();
// clang-format on
}
NGRAPH_TEST(${BACKEND_NAME}, gather_v7_3d_indices_axis_1_batch_dims_1)
{
Shape data_shape{2, 5, 2};
Shape indices_shape{2, 2, 3};
Shape out_shape{2, 2, 3, 2};
int64_t batch_dims = 1;
int64_t axis = 1;
auto P = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto A = op::Constant::create(element::i64, Shape{}, {axis});
auto G = make_shared<op::v7::Gather>(P, I, A, batch_dims);
auto f = make_shared<Function>(G, ParameterVector{P, I});
auto test_case = test::TestCase<TestEngine>(f);
// clang-format off
test_case.add_input<float>({1.0f, 2.0f,
3.0f, 4.0f,
5.0f, 6.0f,
7.0f, 8.0f,
9.0f, 10.0f,
11.0f, 12.0f,
13.0f, 14.0f,
15.0f, 16.0f,
17.0f, 18.0f,
19.0f, 20.0f});
test_case.add_input<int32_t>({0, 0, 4,
4, 0, 0,
1, 2, 4,
4, 3, 2});
test_case.add_expected_output<float>({1.0f, 2.0f,
1.0f, 2.0f,
9.0f, 10.0f,
9.0f, 10.0f,
1.0f, 2.0f,
1.0f, 2.0f,
13.0f, 14.0f,
15.0f, 16.0f,
19.0f, 20.0f,
19.0f, 20.0f,
17.0f, 18.0f,
15.0f, 16.0f});
// clang-format on
test_case.run(MIN_FLOAT_TOLERANCE_BITS);
}

View File

@ -1917,6 +1917,276 @@ TEST(constant_folding, const_gather_v1_subgraph_skip_if_not_single_input)
ASSERT_EQ(count_ops_of_type<op::v1::Gather>(f), 1);
}
TEST(constant_folding, const_gather_v7)
{
auto constant_data = op::Constant::create(
element::f32,
Shape{2, 5},
vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f});
auto constant_indices =
op::Constant::create(element::i64, Shape{4}, vector<int64_t>{0, 3, 2, 2});
auto constant_axis = op::Constant::create(element::i64, Shape{1}, vector<int64_t>{1});
auto gather = make_shared<op::v7::Gather>(constant_data, constant_indices, constant_axis);
gather->set_friendly_name("test");
auto f = make_shared<Function>(gather, ParameterVector{});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 0);
ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
auto new_const =
as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
ASSERT_TRUE(new_const);
ASSERT_EQ(new_const->get_friendly_name(), "test");
auto values_out = new_const->get_vector<float>();
vector<float> values_expected{1.0f, 4.0f, 3.0f, 3.0f, 6.0f, 9.0f, 8.0f, 8.0f};
ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
}
TEST(constant_folding, const_gather_v7_scalar)
{
auto constant_data = op::Constant::create(
element::f32,
Shape{2, 5},
vector<float>{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f});
auto constant_indices =
op::Constant::create(element::i64, Shape{4}, vector<int64_t>{0, 3, 2, 2});
auto constant_axis = op::Constant::create(element::i64, Shape{}, vector<int64_t>{1});
auto gather = make_shared<op::v7::Gather>(constant_data, constant_indices, constant_axis);
gather->set_friendly_name("test");
auto f = make_shared<Function>(gather, ParameterVector{});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 0);
ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
auto new_const =
as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
ASSERT_TRUE(new_const);
ASSERT_EQ(new_const->get_friendly_name(), "test");
auto values_out = new_const->get_vector<float>();
vector<float> values_expected{1.0f, 4.0f, 3.0f, 3.0f, 6.0f, 9.0f, 8.0f, 8.0f};
ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS));
}
TEST(constant_folding, const_gather_v7_subgraph)
{
const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
const float b_value = 3.21f;
const auto B_const = op::Constant::create(element::f32, {1}, {b_value});
const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
const int64_t axis = 0;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B_const, C}, axis);
const vector<int64_t> indices{1};
const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
gather->set_friendly_name("test");
auto f = make_shared<Function>(gather, ParameterVector{A, C});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 0);
ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
const auto new_const =
as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
ASSERT_TRUE(new_const);
ASSERT_EQ(new_const->get_friendly_name(), "test");
const auto values_out = new_const->get_vector<float>();
ASSERT_TRUE(test::all_close_f(values_out, {b_value}, MIN_FLOAT_TOLERANCE_BITS));
}
TEST(constant_folding, const_gather_v7_subgraph_neg_axis)
{
const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
const float b_value = 1.23f;
const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
const auto C_const = op::Constant::create(element::f32, {1}, {b_value});
const int64_t axis = 0;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B, C_const}, axis);
const vector<int64_t> indices{-1};
const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
gather->set_friendly_name("test");
auto f = make_shared<Function>(gather, ParameterVector{A, B});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 0);
ASSERT_EQ(count_ops_of_type<op::Constant>(f), 1);
const auto new_const =
as_type_ptr<op::Constant>(f->get_results().at(0)->input_value(0).get_node_shared_ptr());
ASSERT_TRUE(new_const);
ASSERT_EQ(new_const->get_friendly_name(), "test");
const auto values_out = new_const->get_vector<float>();
ASSERT_TRUE(test::all_close_f(values_out, {b_value}, MIN_FLOAT_TOLERANCE_BITS));
}
TEST(constant_folding, const_gather_v7_subgraph_no_constant_input)
{
const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
const int64_t axis = 0;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
const vector<int64_t> indices{1};
const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
gather->set_friendly_name("test");
auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 0);
}
TEST(constant_folding, const_gather_v7_subgraph_no_constant_input_scalar)
{
const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
const int64_t axis = 0;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
const vector<int64_t> indices{1};
const auto indices_const = op::Constant::create(element::i64, {}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 0);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 0);
ASSERT_EQ(count_ops_of_type<op::v0::Squeeze>(f), 1);
}
TEST(constant_folding, const_gather_v7_subgraph_skip_if_non_zero_axis)
{
const auto A = make_shared<op::Parameter>(element::f32, Shape{2, 2});
const auto B = make_shared<op::Parameter>(element::f32, Shape{2, 2});
const auto C = make_shared<op::Parameter>(element::f32, Shape{2, 2});
const int64_t axis = 1;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
const vector<int64_t> indices{1};
const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 1);
}
TEST(constant_folding, const_gather_v7_subgraph_skip_if_non_single_indices)
{
const auto A = make_shared<op::Parameter>(element::f32, Shape{1});
const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
const int64_t axis = 0;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
const vector<int64_t> indices{0, 1};
const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 1);
}
TEST(constant_folding, const_gather_v7_subgraph_skip_if_concat_output_shape_dynamic)
{
const auto A = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
const int64_t axis = 0;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
const vector<int64_t> indices{1};
const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 1);
}
TEST(constant_folding, const_gather_v7_subgraph_skip_if_not_single_input)
{
const auto A = make_shared<op::Parameter>(element::f32, Shape{2});
const auto B = make_shared<op::Parameter>(element::f32, Shape{1});
const auto C = make_shared<op::Parameter>(element::f32, Shape{1});
const int64_t axis = 0;
const auto axis_const = op::Constant::create(element::i64, {}, {axis});
const auto concat = make_shared<op::Concat>(NodeVector{A, B, C}, axis);
const vector<int64_t> indices{1};
const auto indices_const = op::Constant::create(element::i64, {indices.size()}, indices);
const auto gather = make_shared<op::v7::Gather>(concat, indices_const, axis_const);
auto f = make_shared<Function>(gather, ParameterVector{A, B, C});
pass::Manager pass_manager;
pass_manager.register_pass<pass::ConstantFolding>();
pass_manager.run_passes(f);
ASSERT_EQ(count_ops_of_type<op::Concat>(f), 1);
ASSERT_EQ(count_ops_of_type<op::v7::Gather>(f), 1);
}
TEST(constant_folding, const_strided_slice)
{
Shape shape_in{16};

View File

@ -1197,7 +1197,7 @@ TEST(eval, evaluate_logical_not)
ASSERT_EQ(result_val, expec);
}
TEST(eval, evaluate_dynamic_gather)
TEST(eval, evaluate_dynamic_gather_v1)
{
auto arg1 = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
auto arg2 = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
@ -1216,7 +1216,7 @@ TEST(eval, evaluate_dynamic_gather)
ASSERT_EQ(cval, out);
}
TEST(eval, evaluate_dynamic_axis_gather)
TEST(eval, evaluate_dynamic_gather_v1_scalar_axis)
{
auto arg1 = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
auto arg2 = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
@ -1236,6 +1236,49 @@ TEST(eval, evaluate_dynamic_axis_gather)
ASSERT_EQ(cval, out);
}
TEST(eval, evaluate_dynamic_gather_v7)
{
auto arg1 = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
auto arg2 = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
auto arg3 = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
int64_t batch_dims = 1;
int32_t axis = 1;
auto gather = make_shared<op::v7::Gather>(arg1, arg2, arg3, batch_dims);
auto fun = make_shared<Function>(OutputVector{gather}, ParameterVector{arg1, arg2, arg3});
auto result_tensor = make_shared<HostTensor>();
ASSERT_TRUE(fun->evaluate({result_tensor},
{make_host_tensor<element::Type_t::f32>({2, 3}, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}),
make_host_tensor<element::Type_t::i32>({2, 2}, {1, 0, 1, 0}),
make_host_tensor<element::Type_t::i32>({1}, {axis})}));
EXPECT_EQ(result_tensor->get_element_type(), element::f32);
EXPECT_EQ(result_tensor->get_partial_shape(), (PartialShape{2, 2}));
auto cval = read_vector<float>(result_tensor);
vector<float> out{2.0f, 1.0f, 5.0f, 4.0f};
ASSERT_EQ(cval, out);
}
TEST(eval, evaluate_dynamic_gather_v7_axis_scalar)
{
auto arg1 = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());
auto arg2 = make_shared<op::Parameter>(element::i32, PartialShape::dynamic());
auto arg3 = make_shared<op::Parameter>(element::i64, PartialShape::dynamic());
int64_t batch_dims = 0;
int64_t axis = 1;
auto gather = make_shared<op::v7::Gather>(arg1, arg2, arg3, batch_dims);
auto fun = make_shared<Function>(OutputVector{gather}, ParameterVector{arg1, arg2, arg3});
auto result_tensor = make_shared<HostTensor>();
ASSERT_TRUE(fun->evaluate({result_tensor},
{make_host_tensor<element::Type_t::f32>(
{3, 3}, {1.0f, 1.1f, 1.2f, 2.0f, 2.1f, 2.2f, 3.0f, 3.1f, 3.2f}),
make_host_tensor<element::Type_t::i32>({1, 2}, {0, 2}),
make_host_tensor<element::Type_t::i64>({}, {axis})}));
EXPECT_EQ(result_tensor->get_element_type(), element::f32);
EXPECT_EQ(result_tensor->get_partial_shape(), (PartialShape{3, 1, 2}));
auto cval = read_vector<float>(result_tensor);
vector<float> out{1.0f, 1.2f, 2.0f, 2.2f, 3.0f, 3.2f};
ASSERT_EQ(cval, out);
}
TEST(eval, evaluate_dynamic_concat)
{
auto arg1 = make_shared<op::Parameter>(element::f32, PartialShape::dynamic());

View File

@ -883,8 +883,9 @@ dyn_group_convolution_backprop_data
dynamic_transpose
transpose
# Failing from new reason after unblocking more Blob types
# todo: check negative indices implementation
gather_2d_negative_and_positive_indices_axis_0_2d_input
# Failing from new reason after unblocking more Blob types
gather_axis_0_int8
gather_axis_0_uint8
gather_axis_0_uint32
@ -1582,6 +1583,33 @@ evaluate_mvn_6_across_chanells
evaluate_mvn_6_across_batch
IE_CPU.onnx_mvn_v6
# not yet implemented on CPU/GPU Gather 7
gather_v7_1d_int32
gather_v7_data_int32_3d_indices_axis_1_batch_dims_1
gather_v7_data_int32_2d_indices_axis_1_batch_dims_1
gather_v7_3d_indices_axis_1_batch_dims_1
gather_v7_4d_indices_axis_0_uint8
gather_v7_4d_indices_axis_0_2d_input
gather_v7_3d_indices_axis_0_2d_input
gather_v7_2d_indices_axis_0_2d_input
gather_v7_2d_negative_and_positive_indices_axis_0_2d_input
gather_v7_1d_indices_axis_0_1d_input
gather_v7_scalar_indices_axis_0_2d_input
gather_v7_2d_indices_axis_1_2d_input
gather_v7_1d_indices_axis_2_4d_input
gather_v7_scalar_indices_axis_1_2d_input
gather_v7_axis_0_int8
gather_v7_axis_0_int16
gather_v7_axis_0_int32
gather_v7_axis_0_int64
gather_v7_axis_0_uint8
gather_v7_axis_0_uint16
gather_v7_axis_0_uint32
gather_v7_axis_0_uint64
gather_v7_axis_0_bool
gather_v7_3d_indices_axis_1_batch_dims_1_int32
gather_v7_4d_data_axis_2_batch_dims_1_int32
# Issue 49621: Incorrect blob sizes for node BinaryConvolution_X
bin_convolution_2D_1batch_1channel
bin_convolution_2D_1batch_1channel_padding_pad_val_0

View File

@ -65,6 +65,11 @@ INTERPRETER.gather_axis_0_int8
INTERPRETER.gather_axis_0_int16
INTERPRETER.gather_axis_0_uint8
INTERPRETER.gather_axis_0_uint16
INTERPRETER.gather_v7_4d_indices_axis_0_uint8
INTERPRETER.gather_v7_axis_0_int8
INTERPRETER.gather_v7_axis_0_int16
INTERPRETER.gather_v7_axis_0_uint8
INTERPRETER.gather_v7_axis_0_uint16
INTERPRETER.auto_bcast_binary_elementwise
INTERPRETER.auto_bcast_binary_elementwise_pdpd

View File

@ -395,7 +395,7 @@ TEST(type_prop, gather_7_batch_dims_less_check)
TEST(type_prop, gather_7_batch_dims_less_indices_rank_check)
{
PartialShape data_shape{1, 20, 20, 22, 22};
PartialShape indices_shape{1, 3, 8};
PartialShape indices_shape{1, 3};
auto D = make_shared<op::Parameter>(element::f32, data_shape);
auto I = make_shared<op::Parameter>(element::i64, indices_shape);
@ -413,7 +413,7 @@ TEST(type_prop, gather_7_batch_dims_less_indices_rank_check)
{
EXPECT_HAS_SUBSTRING(
error.what(),
std::string("batch_dims must be < indices_rank"));
std::string("batch_dims must be <= indices_rank"));
}
catch (...)
{