ScatterUpdate ng op shell revision (#7375)

* add visitors, type_prop tests, update ngrap op class

* update NGRPH_RTTI for scatter_update

* add proper formatting for error message

* update opset
This commit is contained in:
Bartek Szmelczynski
2021-09-24 10:31:45 +03:00
committed by GitHub
parent f202c45c46
commit f038fcf2bb
5 changed files with 250 additions and 163 deletions
@@ -0,0 +1,51 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <ngraph/opsets/opset8.hpp>
#include "shared_test_classes/single_layer/scatter_update.hpp"
#include "common_test_utils/test_constants.hpp"
using namespace LayerTestsDefinitions;
using namespace ngraph::opset8;
namespace {
TEST_P(ScatterUpdateLayerTest, Serialize) {
Serialize();
}
const std::vector<InferenceEngine::Precision> inputPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::FP16,
InferenceEngine::Precision::I32,
};
const std::vector<InferenceEngine::Precision> idxPrecisions = {
InferenceEngine::Precision::I32,
InferenceEngine::Precision::I64,
};
// map<inputShape, map<indicesShape, axis>>
std::map<std::vector<size_t>, std::map<std::vector<size_t>, std::vector<int>>> axesShapeInShape {
{{10, 16, 12, 15}, {{{2, 4}, {0, 1, 2, 3}}, {{8}, {-1, -2, -3, -4}}}},
{{10, 9, 10, 9, 10}, {{{8}, {-3, -1, 0, 2, 4}}, {{4, 2}, {-2, 2}}}},
};
//indices should not be random value
const std::vector<std::vector<int64_t>> idxValue = {
{0, 2, 4, 6, 1, 3, 5, 7}
};
const auto ScatterUpdateCase = ::testing::Combine(
::testing::ValuesIn(ScatterUpdateLayerTest::combineShapes(axesShapeInShape)),
::testing::ValuesIn(idxValue),
::testing::ValuesIn(inputPrecisions),
::testing::ValuesIn(idxPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)
);
INSTANTIATE_TEST_SUITE_P(smoke_ScatterUpdate, ScatterUpdateLayerTest, ScatterUpdateCase, ScatterUpdateLayerTest::getTestCaseName);
} // namespace
+12 -5
View File
@@ -59,7 +59,13 @@ void ov::op::util::ScatterBase::validate_and_infer_types() {
this,
data_shape.rank().is_dynamic() || indices_shape.rank().is_dynamic() || updates_shape.rank().is_dynamic() ||
updates_shape.rank().get_length() == indices_shape.rank().get_length() + data_shape.rank().get_length() - 1,
"Updates rank is expected to be indices rank + data rank - 1.");
"Updates rank is expected to be rank(indices) + rank(data) - 1.",
" Got: rank(data) = ",
data_shape.rank().get_length(),
", rank(indices) = ",
indices_shape.rank().get_length(),
", rank(updates) = ",
updates_shape.rank().get_length());
if (data_shape.is_dynamic()) {
set_input_is_relevant_to_shape(0);
@@ -73,20 +79,21 @@ void ov::op::util::ScatterBase::validate_and_infer_types() {
if (const auto& axis_const_input = get_constant_from_source(input_value(AXIS))) {
bool compatible = true;
int64_t axis = axis_const_input->cast_vector<int64_t>().at(0);
axis = ngraph::normalize_axis(this, axis, data_shape.rank().get_length());
int64_t data_rank = data_shape.rank().get_length();
axis = ngraph::normalize_axis(this, axis, data_rank);
if (indices_shape.rank().is_static() && updates_shape.rank().is_static()) {
for (int64_t i = 0; i < indices_shape.rank().get_length(); ++i) {
int64_t indices_rank = indices_shape.rank().get_length();
for (int64_t i = 0; i < indices_rank; ++i) {
compatible = compatible && updates_shape[axis + i].compatible(indices_shape[i]);
}
int64_t indices_rank = indices_shape.rank().get_length();
// Check [d_0, d_1, ... d_(axis - 1)] updates dimensions
for (int64_t i = 0; i < axis; ++i) {
compatible = compatible && updates_shape[i].compatible(data_shape[i]);
}
// Check [d_(axis + k + 1), ..., d_n] updates dimensions
for (int64_t i = axis + 1; i < data_shape.rank().get_length(); ++i) {
for (int64_t i = axis + 1; i < data_rank; ++i) {
compatible = compatible && updates_shape[indices_rank - 1 + i].compatible(data_shape[i]);
}
}
+1
View File
@@ -339,6 +339,7 @@ set(SRC
visitors/op/roi_pooling.cpp
visitors/op/round.cpp
visitors/op/scatter_elements_update.cpp
visitors/op/scatter_update.cpp
visitors/op/select.cpp
visitors/op/space_to_depth.cpp
visitors/op/selu.cpp
+150 -158
View File
@@ -9,197 +9,189 @@
using namespace std;
using namespace ngraph;
TEST(type_prop, scatter_update_v3_fail_indices_element_type) {
namespace {
using type = ngraph::element::Type;
void type_check(const type& refType) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::f32, ref_shape);
auto I = make_shared<op::Parameter>(element::f16, indices_shape);
auto U = make_shared<op::Parameter>(element::f32, updates_shape);
auto A = op::Constant::create(element::i64, Shape{}, {1});
auto R = make_shared<op::Parameter>(refType, ref_shape);
auto I = make_shared<op::Parameter>(element::i32, indices_shape);
auto U = make_shared<op::Parameter>(refType, updates_shape);
auto A = op::Constant::create(element::i32, Shape{1}, {1});
auto scatter_update = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
EXPECT_EQ(scatter_update->get_output_element_type(0), refType);
EXPECT_EQ(scatter_update->get_output_shape(0), ref_shape);
}
void incorrect_type_check(const type& refType,
const type& indicesType,
const type& updatesType,
const type& axisType,
const std::string& errorStr) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(refType, ref_shape);
auto I = make_shared<op::Parameter>(indicesType, indices_shape);
auto U = make_shared<op::Parameter>(updatesType, updates_shape);
auto A = op::Constant::create(axisType, Shape{1}, {1});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect indices element type";
FAIL() << "Incorrect element type of the input";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Indices element type must be of an integral number type"));
EXPECT_HAS_SUBSTRING(error.what(), errorStr);
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
}
void incorrect_shape_check(const Shape& refShape,
const Shape& indicesShape,
const Shape& updatesShape,
const Shape& axisShape,
const float axisVal,
const std::string& errorStr) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::f32, refShape);
auto I = make_shared<op::Parameter>(element::i32, indicesShape);
auto U = make_shared<op::Parameter>(element::f32, updatesShape);
auto A = op::Constant::create(element::i32, axisShape, {axisVal});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect shape of the input";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), errorStr);
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
}
} // namespace
TEST(type_prop, scatter_update_output_type_check_f16) {
type_check(element::f16);
}
TEST(type_prop, scatter_update_output_type_check_f32) {
type_check(element::f32);
}
TEST(type_prop, scatter_update_output_type_check_bf16) {
type_check(element::bf16);
}
TEST(type_prop, scatter_update_output_type_check_i8) {
type_check(element::i8);
}
TEST(type_prop, scatter_update_output_type_check_i16) {
type_check(element::i16);
}
TEST(type_prop, scatter_update_output_type_check_i32) {
type_check(element::i32);
}
TEST(type_prop, scatter_update_output_type_check_i64) {
type_check(element::i64);
}
TEST(type_prop, scatter_update_output_type_check_u8) {
type_check(element::u8);
}
TEST(type_prop, scatter_update_output_type_check_u16) {
type_check(element::u16);
}
TEST(type_prop, scatter_update_output_type_check_u32) {
type_check(element::u32);
}
TEST(type_prop, scatter_update_output_type_check_u64) {
type_check(element::u64);
}
TEST(type_prop, scatter_update_v3_fail_updates_data_et_not_equal) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::f32, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::u32, updates_shape);
auto A = op::Constant::create(element::u32, Shape{1}, {1});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Element types for input data and updates do not match"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
incorrect_type_check(element::f32,
element::i32,
element::u32,
element::i32,
"Element types for input data and updates do not match");
}
TEST(type_prop, scatter_update_v3_fail_indices_element_type) {
incorrect_type_check(element::f32,
element::f16,
element::f32,
element::i64,
"Indices element type must be of an integral number type");
}
TEST(type_prop, scatter_update_v3_fail_axis_element_type) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::i16, ref_shape);
auto I = make_shared<op::Parameter>(element::u64, indices_shape);
auto U = make_shared<op::Parameter>(element::i16, updates_shape);
auto A = op::Constant::create(element::f32, Shape{1}, {1.5f});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Axis element type must be of an integral number type"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
}
TEST(type_prop, scatter_update_v3_fail_axis_shape) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::u8, ref_shape);
auto I = make_shared<op::Parameter>(element::u16, indices_shape);
auto U = make_shared<op::Parameter>(element::u8, updates_shape);
auto A = op::Constant::create(element::u8, Shape{2}, {1, 5});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Axis input shape is required to be scalar or 1D tensor"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
incorrect_type_check(element::i16,
element::u64,
element::i16,
element::f32,
"Axis element type must be of an integral number type");
}
TEST(type_prop, scatter_update_v3_fail_updates_rank) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 1, 4};
auto R = make_shared<op::Parameter>(element::f64, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::f64, updates_shape);
auto A = op::Constant::create(element::u8, Shape{}, {0});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(), std::string("Updates rank is expected to be indices rank + data rank - 1"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
incorrect_shape_check({2, 3, 4},
{2, 1},
{2, 1, 4},
{},
0,
"Updates rank is expected to be rank(indices) + rank(data) - 1");
}
TEST(type_prop, scatter_update_v3_fail_updates_shape_axis) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::u64, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::u64, updates_shape);
auto A = op::Constant::create(element::u16, Shape{}, {0});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("Updates shape must have appropriate dimensions equal to indices and "
"data dimensions"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
incorrect_shape_check({2, 3, 4},
{2, 1},
{2, 2, 1, 4},
{},
0,
"Updates shape must have appropriate dimensions equal to indices and data dimensions");
}
TEST(type_prop, scatter_update_v3_fail_updates_shape_indices) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 3, 1, 4};
auto R = make_shared<op::Parameter>(element::u32, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::u32, updates_shape);
auto A = op::Constant::create(element::i32, Shape{}, {1});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("Updates shape must have appropriate dimensions equal to indices and "
"data dimensions"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
incorrect_shape_check({2, 3, 4},
{2, 1},
{2, 3, 1, 4},
{},
1,
"Updates shape must have appropriate dimensions equal to indices and data dimensions");
}
TEST(type_prop, scatter_update_v3_fail_updates_shape_data_before_axis) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{3, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::u16, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::u16, updates_shape);
auto A = op::Constant::create(element::i8, Shape{}, {1});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("Updates shape must have appropriate dimensions equal to indices and "
"data dimensions"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
incorrect_shape_check({2, 3, 4},
{2, 1},
{3, 2, 1, 4},
{},
1,
"Updates shape must have appropriate dimensions equal to indices and data dimensions");
}
TEST(type_prop, scatter_update_v3_fail_updates_shape_data_after_axis) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 5};
auto R = make_shared<op::Parameter>(element::i8, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::i8, updates_shape);
auto A = op::Constant::create(element::i16, Shape{}, {1});
try {
auto G = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
// Should have thrown, so fail if it didn't
FAIL() << "Incorrect updates element type";
} catch (const NodeValidationFailure& error) {
EXPECT_HAS_SUBSTRING(error.what(),
std::string("Updates shape must have appropriate dimensions equal to indices and "
"data dimensions"));
} catch (...) {
FAIL() << "Deduced type check failed for unexpected reason";
}
incorrect_shape_check({2, 3, 4},
{2, 1},
{2, 2, 1, 5},
{},
1,
"Updates shape must have appropriate dimensions equal to indices and data dimensions");
}
TEST(type_prop, scatter_update_v3) {
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::i8, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::i8, updates_shape);
auto A = op::Constant::create(element::i16, Shape{}, {1});
auto scatter_update = make_shared<op::v3::ScatterUpdate>(R, I, U, A);
EXPECT_EQ(scatter_update->get_output_element_type(0), element::i8);
EXPECT_EQ(scatter_update->get_output_shape(0), ref_shape);
TEST(type_prop, scatter_update_v3_fail_axis_shape) {
incorrect_shape_check({2, 3, 4},
{2, 1},
{2, 2, 1, 4},
{2},
1,
"Axis input shape is required to be scalar or 1D tensor");
}
TEST(type_prop, scatter_update_v3_dynamic_data_shape) {
@@ -0,0 +1,36 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "gtest/gtest.h"
#include "ngraph/ngraph.hpp"
#include "ngraph/op/util/attr_types.hpp"
#include "ngraph/opsets/opset1.hpp"
#include "ngraph/opsets/opset3.hpp"
#include "ngraph/opsets/opset4.hpp"
#include "ngraph/opsets/opset5.hpp"
#include "util/visitor.hpp"
using namespace std;
using namespace ngraph;
using ngraph::test::NodeBuilder;
using ngraph::test::ValueMap;
TEST(attributes, scatter_update_op) {
using namespace opset3;
NodeBuilder::get_ops().register_factory<ScatterUpdate>();
Shape ref_shape{2, 3, 4};
Shape indices_shape{2, 1};
Shape updates_shape{2, 2, 1, 4};
auto R = make_shared<op::Parameter>(element::i8, ref_shape);
auto I = make_shared<op::Parameter>(element::i16, indices_shape);
auto U = make_shared<op::Parameter>(element::i8, updates_shape);
auto A = op::Constant::create(element::i16, Shape{}, {1});
auto op = make_shared<ScatterUpdate>(R, I, U, A);
NodeBuilder builder(op);
const auto expected_attr_count = 0;
EXPECT_EQ(builder.get_value_map_size(), expected_attr_count);
}