diff --git a/inference-engine/src/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp b/inference-engine/src/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp index 9b4f7f80d7f..1d6c10a5909 100644 --- a/inference-engine/src/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp +++ b/inference-engine/src/transformations/include/transformations/common_optimizations/optimize_strided_slice.hpp @@ -68,6 +68,11 @@ public: */ class ngraph::pass::StridedSliceOptimization: public ngraph::pass::FunctionPass { public: + StridedSliceOptimization(bool use_shapes = true); + NGRAPH_RTTI_DECLARATION; bool run_on_function(std::shared_ptr f) override; + +private: + bool m_use_shapes = true; }; diff --git a/inference-engine/src/transformations/include/transformations/op_conversions/convert_slice_to_strided_slice.hpp b/inference-engine/src/transformations/include/transformations/op_conversions/convert_slice_to_strided_slice.hpp new file mode 100644 index 00000000000..8ae55a67065 --- /dev/null +++ b/inference-engine/src/transformations/include/transformations/op_conversions/convert_slice_to_strided_slice.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +namespace ngraph { +namespace pass { + +class TRANSFORMATIONS_API SliceToStridedSlice; + +} // namespace pass +} // namespace ngraph + + +/** + * @ingroup ie_transformation_common_api + * @brief SliceToStridedSlice transformation convert v8::Slice to v1::StridedSlice + */ +class ngraph::pass::SliceToStridedSlice: public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + SliceToStridedSlice(bool use_shapes); +}; diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/moc_transformations.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/moc_transformations.cpp index b67b1811048..88f68a22082 100644 --- a/inference-engine/src/transformations/src/transformations/common_optimizations/moc_transformations.cpp +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/moc_transformations.cpp @@ -91,9 +91,7 @@ bool ngraph::pass::MOCTransformations::run_on_function(std::shared_ptr(); - if (m_use_shapes) { - manager.register_pass(); - } + manager.register_pass(m_use_shapes); manager.register_pass(); diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp index f7b92fb0315..37511260ae4 100644 --- a/inference-engine/src/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/optimize_strided_slice.cpp @@ -6,11 +6,15 @@ #include #include "itt.hpp" +#include "transformations/op_conversions/convert_slice_to_strided_slice.hpp" + #include #include #include +#include #include + NGRAPH_RTTI_DEFINITION(ngraph::pass::StridedSliceOptimization, "StridedSliceOptimization", 0); NGRAPH_RTTI_DEFINITION(ngraph::pass::UselessStridedSliceEraser, "UselessStridedSliceEraser", 0); @@ -245,10 +249,21 @@ bool ngraph::pass::GroupedStridedSliceOptimizer::run_on_function(std::shared_ptr return graph_rewritten; } +ngraph::pass::StridedSliceOptimization::StridedSliceOptimization(bool use_shapes) { + m_use_shapes = use_shapes; +} + bool ngraph::pass::StridedSliceOptimization::run_on_function(std::shared_ptr f) { RUN_ON_FUNCTION_SCOPE(StridedSliceOptimization); - bool rewritten = UselessStridedSliceEraser().run_on_function(f); - rewritten |= SharedStridedSliceEraser().run_on_function(f); - rewritten |= GroupedStridedSliceOptimizer().run_on_function(f); + ngraph::pass::Manager manager(get_pass_config()); + manager.register_pass(m_use_shapes); + manager.run_passes(f); + + bool rewritten = false; + if (m_use_shapes) { + rewritten = UselessStridedSliceEraser().run_on_function(f); + rewritten |= SharedStridedSliceEraser().run_on_function(f); + rewritten |= GroupedStridedSliceOptimizer().run_on_function(f); + } return rewritten; } diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/convert_slice_to_strided_slice.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/convert_slice_to_strided_slice.cpp new file mode 100644 index 00000000000..f0a1e0b6c46 --- /dev/null +++ b/inference-engine/src/transformations/src/transformations/op_conversions/convert_slice_to_strided_slice.cpp @@ -0,0 +1,149 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include +#include +#include + +#include "transformations/op_conversions/convert_slice_to_strided_slice.hpp" +#include "transformations/utils/utils.hpp" +#include "ngraph/node.hpp" +#include "ngraph/op/constant.hpp" +#include "ngraph/op/util/op_types.hpp" +#include "ngraph/validation_util.hpp" + +#include "itt.hpp" + +using namespace ngraph; + +NGRAPH_RTTI_DEFINITION(ngraph::pass::SliceToStridedSlice, "SliceToStridedSlice", 0); + +namespace { + Output align_indices(const Output& indices, + const Output& slice_axes, + const Output& scatter_axis, + size_t slice_indices_length, + int64_t fill_in_value, + NodeVector& new_ops) { + // Handle a case when starts/ends/steps lengths are less than provided axes + // in order to ensure compatibility with `StridedSlice:v1` interface + // Example: + // data_shape: {3, 3, 3, 3} + // starts: [1, 1] - after extending --> [0, 0, 1, 1] + // ends: [2, 2] - after extending --> [0, 0, 2, 2] + // steps : [1, 1] - after extending --> [1, 1, 1, 1] + // axes: [2, 3] - apply slice values to 2 and 3 dimension of input data + // expected_output_shape: {3, 3, 1, 1} + + const auto default_indices = ngraph::opset8::Constant::create(indices.get_element_type(), Shape{slice_indices_length}, {fill_in_value}); + std::shared_ptr adjusted_indices = ngraph::op::util::make_try_fold( + default_indices, + slice_axes, + indices, // updates + scatter_axis); + + if (!ngraph::op::is_constant(adjusted_indices)) { + new_ops.push_back(default_indices); + } + return adjusted_indices; +} + +std::vector axes_to_mask(const std::vector& axes, size_t slice_indices_length) { + std::vector mask(slice_indices_length, 1); + for (auto axis : axes) { + mask[axis] = 0; + } + return mask; +} + +} // namespace + +ngraph::pass::SliceToStridedSlice::SliceToStridedSlice(bool use_shapes) { + MATCHER_SCOPE(SliceToStridedSlice); + auto slice = pattern::wrap_type(); + ngraph::matcher_pass_callback callback = [=](pattern::Matcher& m) { + auto slice_node = std::dynamic_pointer_cast(m.get_match_root()); + if (!slice_node) + return false; + + if (slice_node->get_input_size() < 4) + return false; + + auto arg = slice_node->input_value(0); + + std::shared_ptr start_const; + std::shared_ptr stop_const; + std::shared_ptr step_const; + + if (use_shapes) { + start_const = get_constant_from_source(slice_node->input_value(1)); + stop_const = get_constant_from_source(slice_node->input_value(2)); + step_const = get_constant_from_source(slice_node->input_value(3)); + } else { + start_const = std::dynamic_pointer_cast(slice_node->input_value(1).get_node_shared_ptr()); + stop_const = std::dynamic_pointer_cast(slice_node->input_value(2).get_node_shared_ptr()); + step_const = std::dynamic_pointer_cast(slice_node->input_value(3).get_node_shared_ptr()); + } + + auto start_input = start_const ? start_const : slice_node->input_value(1); + auto stop_input = stop_const ? stop_const : slice_node->input_value(2); + auto step_input = step_const ? step_const : slice_node->input_value(3); + + std::shared_ptr axes_const; + if (slice_node->get_input_size() > 4) { + axes_const = use_shapes ? get_constant_from_source(slice_node->input_value(4)) + : std::dynamic_pointer_cast(slice_node->input_value(4).get_node_shared_ptr()); + } else { + axes_const = slice_node->get_default_const_axes(start_input); + } + if (!axes_const) + return false; + + const auto& data_shape = slice_node->get_input_partial_shape(0); + auto axes_vec = axes_const->cast_vector(); + if (data_shape.rank().is_static()) { + auto norm_axes_vec = normalize_axes(slice_node->get_friendly_name(), axes_vec, data_shape.rank()); + axes_vec = std::vector(norm_axes_vec.begin(), norm_axes_vec.end()); + } else { + const bool need_normalization = std::any_of(axes_vec.begin(), + axes_vec.end(), + [](int64_t axis) { + return axis < 0; + }); + if (need_normalization) + return false; + } + const size_t slice_indices_length = *std::max_element(std::begin(axes_vec), std::end(axes_vec)) + 1; + const auto begin_end_mask = axes_to_mask(axes_vec, slice_indices_length); + + const bool are_axes_sorted = std::is_sorted(axes_vec.begin(), axes_vec.end()); + const bool are_indices_aligned = are_axes_sorted && (axes_vec.size() == slice_indices_length); + + NodeVector new_ops; + if (!are_indices_aligned) { + const auto scatter_axis = opset8::Constant::create(element::i32, Shape{1}, {0}); + const auto slice_axes = opset8::Constant::create(element::i64, Shape{axes_vec.size()}, axes_vec); + new_ops.insert(new_ops.end(), {scatter_axis, slice_axes}); + + start_input = align_indices(start_input, slice_axes, scatter_axis, slice_indices_length, 0, new_ops); + stop_input = align_indices(stop_input, slice_axes, scatter_axis, slice_indices_length, 0, new_ops); + step_input = align_indices(step_input, slice_axes, scatter_axis, slice_indices_length, 1, new_ops); + } + new_ops.insert(new_ops.end(), {start_input.get_node_shared_ptr(), stop_input.get_node_shared_ptr(), step_input.get_node_shared_ptr()}); + + const auto strided_slice = std::make_shared(arg, start_input, stop_input, step_input, begin_end_mask, begin_end_mask); + new_ops.push_back(strided_slice); + + strided_slice->set_friendly_name(slice_node->get_friendly_name()); + ngraph::copy_runtime_info(slice_node, new_ops); + ngraph::replace_node(slice_node, strided_slice); + return true; + }; + + auto m = std::make_shared(slice, matcher_name); + register_matcher(m, callback); +} diff --git a/inference-engine/tests/functional/inference_engine/transformations/optimize_strided_slice_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/optimize_strided_slice_test.cpp index 9c64bd308ce..de7b78bda9d 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/optimize_strided_slice_test.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/optimize_strided_slice_test.cpp @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include "openvino/core/partial_shape.hpp" #include "common_test_utils/ngraph_test_utils.hpp" @@ -277,3 +279,707 @@ TEST_F(TransformationTestsF, OptimizeSS_Groupped_Test) { function_ref = std::make_shared(ngraph::NodeVector{concat}, ngraph::ParameterVector{source}); } } + +TEST_F(TransformationTestsF, OptimizeSS_UselessDeletion_use_shapes_false) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{5, 5, 5, 5}); + auto relu = std::make_shared(data); + auto begin = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto stride = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + + std::vector begin_mask = {0, 0, 0, 0}; + std::vector end_mask = {1, 1, 1, 1}; // ignoring end -- slicing to the end + + auto ss = std::make_shared(relu, begin, end, stride, begin_mask, end_mask); + + function = std::make_shared(ngraph::NodeVector{ss}, ngraph::ParameterVector{data}); + manager.register_pass(false); + manager.register_pass(); + } + // No UselessStridedSliceEraser transformation if use_shapes == false +} + +TEST_F(TransformationTestsF, OptimizeSS_Shared_Test_use_shapes_false) { + { + auto source = std::make_shared(ngraph::element::f32, ngraph::Shape{5, 5, 5, 5}); + + auto begin1 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end1 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto stride1 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + std::vector begin_mask1 = {0, 0, 0, 0}; + std::vector end_mask1 = {0, 0, 0, 0}; + auto ss1 = std::make_shared(source, begin1, end1, stride1, begin_mask1, end_mask1); + + auto begin2 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end2 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto stride2 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + std::vector begin_mask2 = {0, 0, 0, 0}; + std::vector end_mask2 = {0, 0, 0, 0}; + auto ss2 = std::make_shared(source, begin2, end2, stride2, begin_mask2, end_mask2); + + auto concat = std::make_shared(ngraph::NodeVector{ss1, ss2}, 0); + + function = std::make_shared(ngraph::NodeVector{concat}, ngraph::ParameterVector{source}); + manager.register_pass(false); + manager.register_pass(); + } + // No SharedStridedSliceEraser transformation if use_shapes == false +} + +TEST_F(TransformationTestsF, OptimizeSS_Groupped_Test_use_shapes_false) { + { + auto source = std::make_shared(ngraph::element::f32, ngraph::Shape{5, 5, 5, 5}); + + auto begin1 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end1 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {5, 3, 5, 5}); + auto stride1 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + std::vector begin_mask1 = {0, 0, 0, 0}; + std::vector end_mask1 = {0, 0, 0, 0}; + auto ss1 = std::make_shared(source, begin1, end1, stride1, begin_mask1, end_mask1); + + auto begin2 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 3, 0, 0}); + auto end2 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {5, 5, 5, 5}); + auto stride2 = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + std::vector begin_mask2 = {0, 0, 0, 0}; + std::vector end_mask2 = {0, 0, 0, 0}; + auto ss2 = std::make_shared(source, begin2, end2, stride2, begin_mask2, end_mask2); + + auto concat = std::make_shared(ngraph::NodeVector{ss1, ss2}, 1); + + function = std::make_shared(ngraph::NodeVector{concat}, ngraph::ParameterVector{source}); + manager.register_pass(false); + manager.register_pass(); + } + // No GroupedStridedSliceOptimizer transformation if use_shapes == false +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_default_axes) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto step = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1, 1, 1, 1}); + + auto slice = std::make_shared(data, begin, end, step); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data}); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1, 1, 1, 1}); + + std::vector begin_mask = {0, 0, 0, 0}; + std::vector end_mask = {0, 0, 0, 0}; + + auto strided_slice = std::make_shared(data, begin, end, stride, begin_mask, end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_axes_const_sorted_full) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto step = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1, 1, 1, 1}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 1, 2, 3}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data}); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1, 1, 1, 1}); + + std::vector begin_mask = {0, 0, 0, 0}; + std::vector end_mask = {0, 0, 0, 0}; + + auto strided_slice = std::make_shared(data, begin, end, stride, begin_mask, end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_all_const) { + { + auto data = ngraph::opset8::Constant::create(ngraph::element::f32, ngraph::Shape{4}, {2, 3, 4, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {-1}); + auto step = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {-1}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{}); + manager.register_pass(); + } + { + auto data = ngraph::opset8::Constant::create(ngraph::element::f32, ngraph::Shape{4}, {2, 3, 4, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {-1}); + auto stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + + std::vector begin_end_mask = {0}; + auto strided_slice = std::make_shared(data, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_all_const_fold) { + { + auto data = ngraph::opset8::Constant::create(ngraph::element::f32, ngraph::Shape{4}, {2, 3, 4, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {-1}); + auto step = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {-1}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{}); + manager.register_pass(); + manager.register_pass(); + } + { + auto sliced_const = ngraph::opset8::Constant::create(ngraph::element::f32, ngraph::Shape{2}, {3, 4}); + function_ref = std::make_shared(ngraph::NodeVector{sliced_const}, ngraph::ParameterVector{}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_sss_params_axes_const_sorted_less) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 2}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin, end, step}); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto start = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto stop = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {1, 2}); + auto zero = ngraph::opset8::Constant::create(ngraph::element::i32, ngraph::Shape{1}, {0}); + + const auto default_begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {0}); + const auto begin = std::make_shared(default_begin, + axes, + start, + zero); + + const auto default_end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {0}); + const auto end = std::make_shared(default_end, + axes, + stop, + zero); + + const auto default_stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{3}, {1}); + const auto stride = std::make_shared(default_stride, + axes, + step, + zero); + std::vector begin_end_mask = {1, 0, 0}; + auto strided_slice = std::make_shared(data, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data, start, stop, step}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_sss_params_axes_const_unsorted) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {3, 1}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin, end, step}); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto start = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto stop = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + + auto zero = ngraph::opset8::Constant::create(ngraph::element::i32, ngraph::Shape{1}, {0}); + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {3, 1}); + + const auto default_begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + const auto begin = std::make_shared(default_begin, + axes, + start, + zero); + + const auto default_end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + const auto end = std::make_shared(default_end, + axes, + stop, + zero); + + const auto default_stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + const auto stride = std::make_shared(default_stride, + axes, + step, + zero); + + std::vector begin_end_mask = {1, 0, 1, 0}; + auto strided_slice = std::make_shared(data, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data, start, stop, step}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_sss_params_axes_const_negative_sorted) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, -3, 2, -1}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin, end, step}); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto stride = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + + std::vector begin_mask = {0, 0, 0, 0}; + std::vector end_mask = {0, 0, 0, 0}; + + auto strided_slice = std::make_shared(data, begin, end, stride, begin_mask, end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data, begin, end, stride}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_sss_params_dyn_shape_axes_const_negative_unsorted) { + { + auto data_shape = ov::PartialShape{ov::Dimension(-1), ov::Dimension(2, 6), 4, ov::Dimension(-1)}; + auto data = std::make_shared(ngraph::element::f32, data_shape); + auto begin = std::make_shared(ngraph::element::i64, ngraph::PartialShape{ov::Dimension(-1)}); + auto end = std::make_shared(ngraph::element::i64, ngraph::PartialShape{ov::Dimension(-1)}); + auto step = std::make_shared(ngraph::element::i64, ngraph::PartialShape{ov::Dimension(-1)}); + + auto axes = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {-1, -3}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin, end, step}); + manager.register_pass(); + } + { + auto data_shape = ov::PartialShape{ov::Dimension(-1), ov::Dimension(2, 6), 4, ov::Dimension(-1)}; + auto data = std::make_shared(ngraph::element::f32, data_shape); + auto start = std::make_shared(ngraph::element::i64, ngraph::PartialShape{ov::Dimension(-1)}); + auto stop = std::make_shared(ngraph::element::i64, ngraph::PartialShape{ov::Dimension(-1)}); + auto step = std::make_shared(ngraph::element::i64, ngraph::PartialShape{ov::Dimension(-1)}); + + auto zero = ngraph::opset8::Constant::create(ngraph::element::i32, ngraph::Shape{1}, {0}); + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {3, 1}); + + const auto default_begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + const auto begin = std::make_shared(default_begin, + axes, + start, + zero); + + const auto default_end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + const auto end = std::make_shared(default_end, + axes, + stop, + zero); + + const auto default_stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + const auto stride = std::make_shared(default_stride, + axes, + step, + zero); + + std::vector begin_end_mask = {1, 0, 1, 0}; + auto strided_slice = std::make_shared(data, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data, start, stop, step}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_sss_params_static_shape_axes_const_negative_unsorted) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + + auto axes = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {-1, -3}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin, end, step}); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto start = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto stop = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{2}); + + auto zero = ngraph::opset8::Constant::create(ngraph::element::i32, ngraph::Shape{1}, {0}); + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {3, 1}); + + const auto default_begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + const auto begin = std::make_shared(default_begin, + axes, + start, + zero); + + const auto default_end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + const auto end = std::make_shared(default_end, + axes, + stop, + zero); + + const auto default_stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + const auto stride = std::make_shared(default_stride, + axes, + step, + zero); + + std::vector begin_end_mask = {1, 0, 1, 0}; + auto strided_slice = std::make_shared(data, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data, start, stop, step}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_dyn_rank_axes_const_positive) { + { + auto data = std::make_shared(ngraph::element::f32, ov::PartialShape::dynamic()); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 1, 2, 3}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin, end, step}); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ov::PartialShape::dynamic()); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto stride = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + + std::vector begin_mask = {0, 0, 0, 0}; + std::vector end_mask = {0, 0, 0, 0}; + + auto strided_slice = std::make_shared(data, begin, end, stride, begin_mask, end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data, begin, end, stride}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_dyn_rank_axes_const_negative) { + { + auto data = std::make_shared(ngraph::element::f32, ov::PartialShape::dynamic()); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto end = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + auto step = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + + auto axes = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, -3, 2, -1}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin, end, step}); + manager.register_pass(); + manager.register_pass(); + } + // No transformation for negative axes and dynamic data rank +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_axes_param) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 4, 3, 5}); + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0, 0, 0, 0}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {-1, -1, -1, -1}); + auto step = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1, 1, 1, 1}); + + auto axes = std::make_shared(ngraph::element::i64, ngraph::Shape{4}); + + auto slice = std::make_shared(data, begin, end, step, axes); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, axes}); + manager.register_pass(); + manager.register_pass(); + } + // No transformation for non-const axes input +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_begin_param_shape_of_use_shapes_true) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto shape_of_data = std::make_shared(data, ngraph::element::i64); + auto data_rank = std::make_shared(shape_of_data, ngraph::element::i64); + + auto zero_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {0}); + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + auto three_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {3}); + + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{1}); + auto end = std::make_shared(three_const, begin); + auto step = std::make_shared(one_const, begin); + + auto axes = std::make_shared(zero_const, one_const, one_const, ngraph::element::i64); + + auto slice = std::make_shared(shape_of_data, begin, end, step, axes); + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin}); + + manager.register_pass(true); + manager.register_pass(); + } + { + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + auto three_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {3}); + + auto data = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {2, 3, 4, 5}); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{1}); + auto end = std::make_shared(three_const, begin); + auto stride = std::make_shared(one_const, begin); + + std::vector begin_end_mask = {0}; + auto strided_slice = std::make_shared(data, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{begin}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_begin_param_shape_of_use_shapes_false) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto shape_of_data = std::make_shared(data, ngraph::element::i64); + auto data_rank = std::make_shared(shape_of_data, ngraph::element::i64); + + auto zero_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {0}); + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + auto three_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {3}); + + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{1}); + auto end = std::make_shared(three_const, begin); + auto step = std::make_shared(one_const, begin); + + auto axes = std::make_shared(zero_const, one_const, one_const, ngraph::element::i64); + + auto slice = std::make_shared(shape_of_data, begin, end, step, axes); + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data, begin}); + + manager.register_pass(); + manager.register_pass(false); + manager.register_pass(); + } + { + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + auto three_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {3}); + + auto data = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {2, 3, 4, 5}); + auto begin = std::make_shared(ngraph::element::i64, ngraph::Shape{1}); + auto end = std::make_shared(three_const, begin); + auto stride = std::make_shared(one_const, begin); + + std::vector begin_end_mask = {0}; + auto strided_slice = std::make_shared(data, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{begin}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_const_fold_params_slice_shape_of_use_shapes_true) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto shape_of_data = std::make_shared(data, ngraph::element::i64); + auto data_rank = std::make_shared(shape_of_data, ngraph::element::i64); + + auto zero_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {0}); + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + auto three_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {3}); + + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + auto end = std::make_shared(three_const, begin); + auto step = std::make_shared(one_const, begin); + + auto axes = std::make_shared(zero_const, one_const, one_const, ngraph::element::i64); + + auto slice = std::make_shared(shape_of_data, begin, end, step, axes); + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data}); + + manager.register_pass(); + manager.register_pass(true); + manager.register_pass(); + } + { + auto sliced_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {3, 4}); + function_ref = std::make_shared(ngraph::NodeVector{sliced_const}, ngraph::ParameterVector{}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_const_fold_params_slice_shape_of_use_shapes_false) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto shape_of_data = std::make_shared(data, ngraph::element::i64); + auto data_rank = std::make_shared(shape_of_data, ngraph::element::i64); + + auto zero_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {0}); + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + auto three_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {3}); + + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}); + auto end = std::make_shared(three_const, begin); + auto step = std::make_shared(one_const, begin); + + auto axes = std::make_shared(zero_const, one_const, one_const, ngraph::element::i64); + + auto slice = std::make_shared(shape_of_data, begin, end, step, axes); + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data}); + + manager.register_pass(); + manager.register_pass(false); + manager.register_pass(); + } + { + auto sliced_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{2}, {3, 4}); + function_ref = std::make_shared(ngraph::NodeVector{sliced_const}, ngraph::ParameterVector{}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_slice_all_use_shapes_true) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto relu = std::make_shared(data); + + auto shape_of_data = std::make_shared(relu, ngraph::element::i64); + auto data_rank = std::make_shared(shape_of_data, ngraph::element::i64); + + auto zero_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {0}); + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + + auto begin = std::make_shared(zero_const, data_rank); + auto end = std::make_shared(data_rank, data_rank); + auto step = std::make_shared(one_const, data_rank); + + auto slice = std::make_shared(relu, begin, end, step); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data}); + manager.register_pass(true); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto relu = std::make_shared(data); + + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {4}); + auto stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + + std::vector begin_end_mask = {0, 0, 0, 0}; + auto strided_slice = std::make_shared(relu, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} + +TEST_F(TransformationTestsF, SliceToStridedSlice_slice_all_use_shapes_false) { + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto relu = std::make_shared(data); + + auto shape_of_data = std::make_shared(relu, ngraph::element::i64); + auto data_rank = std::make_shared(shape_of_data, ngraph::element::i64); + + auto zero_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {0}); + auto one_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{}, {1}); + + auto begin = std::make_shared(zero_const, data_rank); + auto end = std::make_shared(data_rank, data_rank); + auto step = std::make_shared(one_const, data_rank); + + auto slice = std::make_shared(relu, begin, end, step); + + function = std::make_shared(ngraph::NodeVector{slice}, ngraph::ParameterVector{data}); + manager.register_pass(false); + manager.register_pass(); + } + { + auto data = std::make_shared(ngraph::element::f32, ngraph::Shape{2, 3, 4, 5}); + auto relu = std::make_shared(data); + + auto begin = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {0}); + auto end = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {4}); + auto stride = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{4}, {1}); + + std::vector begin_end_mask = {0, 0, 0, 0}; + auto strided_slice = std::make_shared(relu, begin, end, stride, begin_end_mask, begin_end_mask); + + function_ref = std::make_shared(ngraph::NodeVector{strided_slice}, ngraph::ParameterVector{data}); + } + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); +} diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/slice.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/slice.cpp new file mode 100644 index 00000000000..2543d44f99d --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/slice.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "single_layer_tests/slice.hpp" +#include "common_test_utils/test_constants.hpp" + +using namespace LayerTestsDefinitions; + +namespace { + +const std::vector inputPrecision = { + InferenceEngine::Precision::I8, + InferenceEngine::Precision::U8, + InferenceEngine::Precision::I16, + InferenceEngine::Precision::I32, + InferenceEngine::Precision::FP32 +}; + +std::vector test_cases = { + SliceSpecificParams{ { 16 }, { 4 }, { 12 }, { 1 }, { 0 } }, + SliceSpecificParams{ { 16 }, { 0 }, { 8 }, { 2 }, { 0 } }, + SliceSpecificParams{ { 20, 10, 5 }, { 0, 0}, { 10, 20}, { 1, 1 }, { 1, 0 } }, + SliceSpecificParams{ { 1, 2, 12, 100 }, { 0, 1, 0, 1 }, { 1, 2, 5, 100 }, { 1, 1, 1, 10 }, {} }, + SliceSpecificParams{ { 1, 12, 100 }, { 0, 9, 0 }, { 1, 11, 1 }, { 1, 1, 1 }, {} }, + SliceSpecificParams{ { 1, 12, 100 }, { 0, 1, 0 }, { 10, -1, 10 }, { 1, 1, 1 }, {} }, + SliceSpecificParams{ { 2, 12, 100 }, { 1, 12, 100 }, { 0, 7, 0 }, { -1, -1, -1 }, {} }, + SliceSpecificParams{ { 2, 12, 100 }, { 1, 4, 99 }, { 0, 9, 0 }, { -1, 2, -1 }, {} }, + SliceSpecificParams{ { 2, 12, 100 }, { -1, -1, -1 }, { 0, 4, 0 }, { -1, -2, -1 }, {} }, + SliceSpecificParams{ { 2, 12, 100 }, { -1, -1, -1 }, { 0, 0, 4 }, { -1, -1, -1 }, {2, 0, 1} }, + SliceSpecificParams{ { 2, 12, 100 }, { 0, 0, 4 }, { -5, -1, -1 }, { 1, 2, 1 }, {2, 0, 1} }, + SliceSpecificParams{ { 2, 2, 2, 2 }, { 0, 0, 0, 0 }, { 2, 2, 2, 2 }, { 1, 1, 1, 1 }, {} }, + SliceSpecificParams{ { 2, 2, 2, 2 }, { 1, 1, 1, 1 }, { 2, 2, 2, 2 }, { 1, 1, 1, 1 }, {} }, + SliceSpecificParams{ { 2, 2, 4, 3 }, { 0, 0, 0, 0 }, { 2, 2, 4, 3 }, { 1, 1, 2, 1 }, {} }, + SliceSpecificParams{ { 2, 2, 4, 2 }, { 1, 0, 0, 1 }, { 2, 2, 4, 2 }, { 1, 1, 2, 1 }, {} }, + SliceSpecificParams{ { 1, 2, 4, 2 }, { 0, 1, 0, 1 }, { 10, 2, 4, 2 }, { 1, 1, 2, 1 }, {} }, + SliceSpecificParams{ { 10, 2, 4, 2 }, { 9, 1, 3, 0 }, { 0, 0, 0, 1 }, { -1, -1, -1, 1 }, {} }, + SliceSpecificParams{ { 10, 2, 4, 2 }, { 19, 1, -1, 0 }, { -10, 0, 0, -1 }, { -1, -1, -1, 1 }, {} }, + SliceSpecificParams{ { 3, 2, 4, 200 }, { 0, 1, -1, -1 }, { 3, 2, 0, 0 }, { 1, 1, -2, -1 }, {} }, + SliceSpecificParams{ { 2, 4, 5, 5, 68 }, { 0, 1, 0, 0, 0 }, { + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max() }, { 1, 1, 1, 1, 16 }, {} }, + SliceSpecificParams{ { 10, 12 }, { -1, 1 }, { -9999, 10 }, { -1, 1 }, {} }, + SliceSpecificParams{ { 5, 5, 5, 5 }, { -1, 0, -1, 0 }, { -50, -1, -60, -1 }, { -1, 1, -1, 1 }, {} }, + SliceSpecificParams{ { 1, 5, 32, 32 }, { 0, 2, 5, 4 }, { 1, 4, 28, 27 }, { 1, 1, 1, 1 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 1, 5, 32, 20 }, { 0, 1, 0, 0 }, { 1, 3, 32, 20 }, { 1, 1, 1, 1 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 2, 5, 32, 20 }, { 0, 0, 10, 0 }, { 1, 3, 20, 20 }, { 1, 1, 1, 1 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 1, 5, 32, 32 }, { 0, 0, 20, 20 }, { 1, 5, 25, 26 }, { 1, 1, 1, 2 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 2, 5, 32, 32 }, { 0, 0, 0, 20 }, { 1, 2, 30, 30 }, { 1, 1, 2, 1 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 1, 5, 32, 20 }, { 0, 0, 2, 10 }, { 1, 3, 32, 20 }, { 1, 1, 1, 1 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 2, 5, 32, 32 }, { 0, 1, 0, 10 }, { 1, 5, 32, 30 }, { 1, 1, 1, 1 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 1, 5, 32, 20 }, { 0, 1, 2, 10 }, { 1, 5, 32, 18 }, { 1, 1, 1, 2 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 2, 8, 32, 20 }, { 0, 0, 2, 10 }, { 1, 8, 32, 18 }, { 1, 2, 1, 2 }, { 0, 1, 2, 3 } }, + SliceSpecificParams{ { 2, 8, 32, 20 }, { 0, -20, -15 }, { 2, -5, 3 }, { 1, 1, 1 }, { 0, 2, 1 } }, + + // Plugin Error: Slice has zero dimension which is not allowed + // SliceSpecificParams{ { 2, 8, 32, 20 }, { 0, 0, 10 }, { 0, 32, 18 }, { 1, 1, 1 }, { 0, 1, 2 } }, + // SliceSpecificParams{ { 2, 8, 32, 20 }, { 0, 0, 10 }, { 1, 0, 20 }, { 1, 1, 1 }, { 0, 1, 2 } }, + // SliceSpecificParams{ { 2, 8, 32, 20 }, { 0, 4, 10 }, { 2, 8, 0 }, { 1, 1, 1 }, { 0, 1, 2 } }, + // SliceSpecificParams{ { 2, 8, 32, 20 }, { 0, 4, 10 }, { 2, 8, 0 }, { 1, 1, 1 }, { 0, 2, 1 } }, + // SliceSpecificParams{ { 2, 8, 32, 20 }, { 0, 4, 10 }, { 2, 8, 0 }, { 1, 1, 1 }, { 0, -2, -1 } }, +}; + +INSTANTIATE_TEST_SUITE_P( + smoke_MKLDNN, SliceLayerTest, + ::testing::Combine( + ::testing::ValuesIn(test_cases), + ::testing::ValuesIn(inputPrecision), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(CommonTestUtils::DEVICE_CPU), + ::testing::Values(std::map())), + SliceLayerTest::getTestCaseName); + +} // namespace diff --git a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/slice.hpp b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/slice.hpp new file mode 100644 index 00000000000..cf432f4ada6 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/slice.hpp @@ -0,0 +1,13 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "shared_test_classes/single_layer/slice.hpp" + +namespace LayerTestsDefinitions { +TEST_P(SliceLayerTest, CompareWithRefs) { + Run(); +} +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/shared_test_classes/include/shared_test_classes/single_layer/slice.hpp b/inference-engine/tests/functional/shared_test_classes/include/shared_test_classes/single_layer/slice.hpp new file mode 100644 index 00000000000..946cc4e0ad7 --- /dev/null +++ b/inference-engine/tests/functional/shared_test_classes/include/shared_test_classes/single_layer/slice.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include + +#include "shared_test_classes/base/layer_test_utils.hpp" + +namespace LayerTestsDefinitions { + +struct SliceSpecificParams { + InferenceEngine::SizeVector inputShape; + std::vector start; + std::vector stop; + std::vector step; + std::vector axes; +}; + +using SliceParams = std::tuple< + SliceSpecificParams, + InferenceEngine::Precision, // Net precision + InferenceEngine::Precision, // Input precision + InferenceEngine::Precision, // Output precision + InferenceEngine::Layout, // Input layout + InferenceEngine::Layout, // Output layout + std::string, // Device name + std::map // Additional network configuration +>; + +class SliceLayerTest : public testing::WithParamInterface, + virtual public LayerTestsUtils::LayerTestsCommon { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj); + +protected: + void SetUp() override; +}; +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/shared_test_classes/src/single_layer/slice.cpp b/inference-engine/tests/functional/shared_test_classes/src/single_layer/slice.cpp new file mode 100644 index 00000000000..60130e82480 --- /dev/null +++ b/inference-engine/tests/functional/shared_test_classes/src/single_layer/slice.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph_functions/builders.hpp" +#include "ngraph/ngraph.hpp" + +#include "shared_test_classes/single_layer/slice.hpp" + +using namespace ngraph; + +namespace LayerTestsDefinitions { + +std::string SliceLayerTest::getTestCaseName(const testing::TestParamInfo &obj) { + SliceSpecificParams params; + InferenceEngine::Precision netPrc; + InferenceEngine::Precision inPrc, outPrc; + InferenceEngine::Layout inLayout, outLayout; + std::string targetName; + std::map additionalConfig; + std::tie(params, netPrc, inPrc, outPrc, inLayout, outLayout, targetName, additionalConfig) = obj.param; + std::ostringstream result; + result << "inShape=" << CommonTestUtils::vec2str(params.inputShape) << "_"; + result << "netPRC=" << netPrc.name() << "_"; + result << "start=" << CommonTestUtils::vec2str(params.start) << "_"; + result << "stop=" << CommonTestUtils::vec2str(params.stop) << "_"; + result << "step=" << CommonTestUtils::vec2str(params.step) << "_"; + result << "axes=" << CommonTestUtils::vec2str(params.axes) << "_"; + result << "trgDev=" << targetName; + return result.str(); +} + +void SliceLayerTest::SetUp() { + SliceSpecificParams sliceParams; + InferenceEngine::Precision netPrecision; + std::map additionalConfig; + std::tie(sliceParams, netPrecision, inPrc, outPrc, inLayout, outLayout, targetDevice, additionalConfig) = this->GetParam(); + configuration.insert(additionalConfig.begin(), additionalConfig.end()); + + auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); + + element::Type_t et = element::i32; + + const auto data = std::make_shared(ngPrc, Shape(sliceParams.inputShape)); + const auto start = std::make_shared(et, Shape{sliceParams.start.size()}, sliceParams.start); + const auto stop = std::make_shared(et, Shape{sliceParams.stop.size()}, sliceParams.stop); + const auto step = std::make_shared(et, Shape{sliceParams.step.size()}, sliceParams.step); + + Output slice; + if (sliceParams.axes.empty()) { + slice = std::make_shared(data, start, stop, step); + } else { + const auto axes = std::make_shared(et, Shape{sliceParams.axes.size()}, sliceParams.axes); + slice = std::make_shared(data, start, stop, step, axes); + } + + ResultVector results{std::make_shared(slice)}; + function = std::make_shared(results, ov::ParameterVector{data}, "Slice"); +} + +} // namespace LayerTestsDefinitions diff --git a/ngraph/core/include/openvino/op/slice.hpp b/ngraph/core/include/openvino/op/slice.hpp index f35cd715982..caa5d365781 100644 --- a/ngraph/core/include/openvino/op/slice.hpp +++ b/ngraph/core/include/openvino/op/slice.hpp @@ -32,6 +32,7 @@ public: std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; + std::shared_ptr get_default_const_axes(const Output& start) const; PartialShape calculate_output_shape(const std::vector& starts, const std::vector& stops, const std::vector& steps, diff --git a/ngraph/core/src/op/slice.cpp b/ngraph/core/src/op/slice.cpp index 0c4c9de122f..0488b1acee2 100644 --- a/ngraph/core/src/op/slice.cpp +++ b/ngraph/core/src/op/slice.cpp @@ -10,6 +10,7 @@ #include "ngraph/attribute_visitor.hpp" #include "ngraph/graph_util.hpp" #include "ngraph/op/constant.hpp" +#include "ngraph/runtime/reference/slice.hpp" #include "ngraph/validation_util.hpp" using namespace std; @@ -34,19 +35,6 @@ op::v8::Slice::Slice(const Output& data, namespace { -std::shared_ptr get_default_const_axes(const Output& start) { - const auto start_pshape = start.get_partial_shape(); - // Static case - if (start_pshape.rank().is_static() && start_pshape.rank().get_length() == 1 && start_pshape[0].is_static()) { - size_t axes_length = start_pshape[0].get_length(); - std::vector axes(axes_length); - std::iota(axes.begin(), axes.end(), 0); - return op::v0::Constant::create(element::i64, Shape{axes_length}, axes); - } - // Dynamic case - return nullptr; -} - int64_t get_sliced_dim_size(int64_t start, int64_t stop, int64_t step, int64_t dim_size) { // Normalize index start = start < 0 ? dim_size + start : start; @@ -64,7 +52,9 @@ int64_t get_sliced_dim_size(int64_t start, int64_t stop, int64_t step, int64_t d // Clip max stop index (last element exclusively) elements_in_range = std::max(int64_t(0), std::min(dim_size, stop) - start); } - const int64_t sliced_dim_size = std::ceil(elements_in_range / std::fabs(step)); + const int64_t rest = elements_in_range % std::abs(step); + const int64_t integer_div = elements_in_range / std::abs(step); + const int64_t sliced_dim_size = !rest ? integer_div : integer_div + 1; return sliced_dim_size; } @@ -75,6 +65,19 @@ bool op::v8::Slice::visit_attributes(AttributeVisitor& visitor) { return true; } +std::shared_ptr op::v8::Slice::get_default_const_axes(const Output& start) const { + const auto start_pshape = start.get_partial_shape(); + // Static case + if (start_pshape.rank().is_static() && start_pshape.rank().get_length() == 1 && start_pshape[0].is_static()) { + size_t axes_length = start_pshape[0].get_length(); + std::vector axes(axes_length); + std::iota(axes.begin(), axes.end(), 0); + return op::v0::Constant::create(element::i64, Shape{axes_length}, axes); + } + // Dynamic case + return nullptr; +} + void op::v8::Slice::validate_and_infer_types() { NGRAPH_OP_SCOPE(v8_Slice_validate_and_infer_types);