From bb44f17a062ea6fea9e3a3bb6d62c14902f98389 Mon Sep 17 00:00:00 2001 From: Evgenya Stepyreva Date: Thu, 18 Jun 2020 11:36:07 +0300 Subject: [PATCH] [ DTS ] Reduces (#940) --- .../dynamic_to_static_shape_reduce.hpp | 15 ++ .../dynamic_to_static_shape.cpp | 10 ++ .../dynamic_to_static_shape_reduce.cpp | 71 ++++++++ .../dynamic_to_static_shape_reduce.cpp | 166 ++++++++++++++++++ .../myriad/subgraph_tests/dsr_reduce.cpp | 110 ++++++++++++ ngraph/src/ngraph/validation_util.cpp | 7 +- 6 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_reduce.hpp create mode 100644 inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_reduce.cpp create mode 100644 inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_reduce.cpp create mode 100644 inference-engine/tests/functional/plugin/myriad/subgraph_tests/dsr_reduce.cpp diff --git a/inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_reduce.hpp b/inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_reduce.hpp new file mode 100644 index 00000000000..880b9be50c1 --- /dev/null +++ b/inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_reduce.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "ngraph/node.hpp" + +#include + +namespace vpu { + +void dynamicToStaticShapeReduce(std::shared_ptr node); + +} // namespace vpu diff --git a/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape.cpp b/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape.cpp index f9255d83af9..6843d5a2d4c 100644 --- a/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape.cpp +++ b/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape.cpp @@ -5,6 +5,7 @@ #include "vpu/ngraph/transformations/dynamic_to_static_shape_broadcast.hpp" #include "vpu/ngraph/transformations/dynamic_to_static_shape_concat.hpp" #include "vpu/ngraph/transformations/dynamic_to_static_shape_unary_elementwise.hpp" +#include "vpu/ngraph/transformations/dynamic_to_static_shape_reduce.hpp" #include "vpu/ngraph/transformations/dynamic_to_static_shape_roialign.hpp" #include "vpu/ngraph/transformations/dynamic_to_static_shape_topk.hpp" #include "vpu/ngraph/transformations/dynamic_to_static_shape_transpose.hpp" @@ -86,6 +87,15 @@ const Transformations& getDefaultTransformations() { {ngraph::opset3::ROIAlign::type_info, dynamicToStaticShapeROIAlign}, {ngraph::opset3::Reshape::type_info, dynamicToStaticShapeReshape}, {ngraph::opset3::Broadcast::type_info, dynamicToStaticShapeBroadcast}, + + // reduction + {ngraph::opset3::ReduceLogicalAnd::type_info, dynamicToStaticShapeReduce}, + {ngraph::opset3::ReduceLogicalOr::type_info, dynamicToStaticShapeReduce}, + {ngraph::opset3::ReduceMax::type_info, dynamicToStaticShapeReduce}, + {ngraph::opset3::ReduceMean::type_info, dynamicToStaticShapeReduce}, + {ngraph::opset3::ReduceMin::type_info, dynamicToStaticShapeReduce}, + {ngraph::opset3::ReduceProd::type_info, dynamicToStaticShapeReduce}, + {ngraph::opset3::ReduceSum::type_info, dynamicToStaticShapeReduce}, }; return transformations; } diff --git a/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_reduce.cpp b/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_reduce.cpp new file mode 100644 index 00000000000..50a60c8a5c2 --- /dev/null +++ b/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_reduce.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "vpu/ngraph/transformations/dynamic_to_static_shape_reduce.hpp" +#include "vpu/ngraph/operations/dynamic_shape_resolver.hpp" + +#include +#include "ngraph/graph_util.hpp" + +#include "ngraph/opsets/opset3.hpp" +#include +#include +#include + +namespace vpu { + +void dynamicToStaticShapeReduce(std::shared_ptr target) { + const auto dsr = ngraph::as_type_ptr(target->input_value(0).get_node_shared_ptr()); + VPU_THROW_UNLESS(dsr, "DynamicToStaticShape transformation for {} of type {} expects {} as input with index {}", + target->get_friendly_name(), target->get_type_info(), ngraph::vpu::op::DynamicShapeResolver::type_info, 0); + + VPU_THROW_UNLESS(std::dynamic_pointer_cast(target) || + std::dynamic_pointer_cast(target), + "dynamicToStaticShapeReduce transformation expects arithmetic or logical reduction, but it got {} node of type {}", + target->get_friendly_name(), target->get_type_info()); + + + const auto axes_const_node = ngraph::as_type_ptr(target->get_argument(1)); + VPU_THROW_UNLESS(axes_const_node, + "dynamicToStaticShapeReduce transformation for {} of type {} expects {} as input with index {}, but it has {} node of type {} instead", + target->get_friendly_name(), target->get_type_info(), ngraph::opset3::Constant::type_info, 1, + target->get_argument(1)->get_friendly_name(), target->get_argument(1)->get_type_info()); + + const auto axes = axes_const_node->cast_vector(); + + const auto data_rank = target->get_input_partial_shape(0).rank(); + VPU_THROW_UNLESS(data_rank.is_static(), "dynamicToStaticShapeReduce transformation for {} doesn't support dynamic rank", target); + const auto data_rank_value = data_rank.get_length(); + + bool keep_dims = false; + if (const auto arithmetic_reduce = std::dynamic_pointer_cast(target)) { + keep_dims = arithmetic_reduce->get_keep_dims(); + } else if (const auto logical_reduce = std::dynamic_pointer_cast(target)) { + keep_dims = logical_reduce->get_keep_dims(); + } // assertion earlier excluded other variants + + const auto data_shape = dsr->input_value(1); + ngraph::Output output_shape; + if (keep_dims) { + output_shape = std::make_shared( + data_shape, + ngraph::opset3::Constant::create(ngraph::element::i64, {axes.size()}, axes), + ngraph::opset3::Constant::create(ngraph::element::i64, {axes.size()}, std::vector(axes.size(), 1)), + ngraph::opset3::Constant::create(ngraph::element::i64, {1}, {0})); + } else { + std::vector range(data_rank_value); + std::iota(range.begin(), range.end(), 0); + std::vector indices; + std::copy_if(range.cbegin(), range.cend(), std::back_inserter(indices), + [&axes](int64_t i) { return std::find(axes.cbegin(), axes.cend(), i) == axes.cend(); }); + + output_shape = std::make_shared( + data_shape, + ngraph::opset3::Constant::create(ngraph::element::i64, {indices.size()}, indices), + ngraph::opset3::Constant::create(ngraph::element::i64, {1}, {0})); + } + const auto copied = target->clone_with_new_inputs(target->input_values()); + ngraph::replace_node(target, std::make_shared(copied, output_shape)); +} +} // namespace vpu diff --git a/inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_reduce.cpp b/inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_reduce.cpp new file mode 100644 index 00000000000..12ac7e51cad --- /dev/null +++ b/inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_reduce.cpp @@ -0,0 +1,166 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using DataType = ngraph::element::Type_t; +using DataDims = ngraph::Shape; + +struct ReduceTestCase { + ngraph::Shape data_shape; + std::vector axes; + bool keep_dims; + std::vector gather_indices; +}; + +const auto arithmetic_combinations = testing::Combine( + testing::Values( + ngraph::opset3::ReduceMax::type_info, + ngraph::opset3::ReduceMean::type_info, + ngraph::opset3::ReduceMin::type_info, + ngraph::opset3::ReduceProd::type_info, + ngraph::opset3::ReduceSum::type_info), + testing::Values( + ngraph::element::f16, + ngraph::element::f32, + ngraph::element::i32, + ngraph::element::i64, + ngraph::element::u8), + testing::Values( + ngraph::element::i32, + ngraph::element::i64, + ngraph::element::u8), + testing::Values( + // data_shape, axes, keep_dims, gather_indices, axes_shape + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, true, {1, 1}}, + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, false, {0, 1}}, + ReduceTestCase{{1, 3, 224, 224}, {0, 1, 2, 3}, true, {1, 1, 1, 1}}, + ReduceTestCase{{1, 3, 224, 224}, {1, 3}, false, {0, 2}}, + ReduceTestCase{{4}, {0}, true, {1}})); + +const auto logical_combinations = testing::Combine( + testing::Values( + ngraph::opset3::ReduceLogicalAnd::type_info, + ngraph::opset3::ReduceLogicalOr::type_info), + testing::Values(ngraph::element::boolean), + testing::Values( + ngraph::element::i32, + ngraph::element::i64, + ngraph::element::u8), + testing::Values( + // data_shape, axes, keep_dims, gather_indices + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, true, {1, 1}}, + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, false, {0, 1}}, + ReduceTestCase{{1, 3, 224, 224}, {0, 1, 2, 3}, true, {1, 1, 1, 1}}, + ReduceTestCase{{1, 3, 224, 224}, {1, 3}, false, {0, 2}}, + ReduceTestCase{{4}, {0}, true, {1}})); + +class DynamicToStaticShapeReduce: public CommonTestUtils::TestsCommon, + public testing::WithParamInterface> { +public: + void SetUp() override { + const auto& parameters = GetParam(); + const auto& reduce_type = std::get<0>(parameters); + const auto& data_type = std::get<1>(parameters); + const auto& axes_type = std::get<2>(parameters); + const auto& reduce_setup = std::get<3>(parameters); + + ngraph::helpers::CompareFunctions(*transform(reduce_type, data_type, axes_type, reduce_setup), + *reference(reduce_type, data_type, axes_type, reduce_setup)); + } + +protected: + std::shared_ptr transform( + const ngraph::NodeTypeInfo type_info, + const ngraph::element::Type_t& data_type, + const ngraph::element::Type_t& axes_type, + const ReduceTestCase& reduce_setup) const { + const auto data = std::make_shared(data_type, reduce_setup.data_shape); + const auto axes = ngraph::opset3::Constant::create(axes_type, {reduce_setup.axes.size()}, reduce_setup.axes); + + const auto dims = std::make_shared(ngraph::element::i64, ngraph::Shape{reduce_setup.data_shape.size()}); + + const auto dsr = std::make_shared(data, dims); + const auto node = ngraph::helpers::getNodeSharedPtr(type_info, {dsr, axes}); + + if (auto arithmetic_reduce = std::dynamic_pointer_cast(node)) + arithmetic_reduce->set_keep_dims(reduce_setup.keep_dims); + else if (auto logical_reduce = std::dynamic_pointer_cast(node)) + logical_reduce->set_keep_dims(reduce_setup.keep_dims); + node->validate_and_infer_types(); + + auto outputShape = node->get_output_partial_shape(0); + const auto function = std::make_shared( + ngraph::NodeVector{node}, + ngraph::ParameterVector{data, dims}, + "Actual"); + node->set_output_type(0, data_type, ngraph::PartialShape::dynamic(node->get_output_partial_shape(0).rank())); + const auto transformations = vpu::Transformations{{type_info, vpu::dynamicToStaticShapeReduce}}; + vpu::DynamicToStaticShape(transformations).transform(function); + return function; + } + + std::shared_ptr reference( + const ngraph::NodeTypeInfo type_info, + const ngraph::element::Type_t& data_type, + const ngraph::element::Type_t& axes_type, + const ReduceTestCase& reduce_setup) const { + const auto data = std::make_shared(data_type, reduce_setup.data_shape); + const auto axes = ngraph::opset3::Constant::create(axes_type, {reduce_setup.axes.size()}, reduce_setup.axes); + + const auto dims = std::make_shared(ngraph::element::i64, ngraph::Shape{reduce_setup.data_shape.size()}); + + const auto dsr = std::make_shared(data, dims); + const auto node = ngraph::helpers::getNodeSharedPtr(type_info, {dsr, axes}); + + if (auto arithmetic_reduce = std::dynamic_pointer_cast(node)) + arithmetic_reduce->set_keep_dims(reduce_setup.keep_dims); + else if (auto logical_reduce = std::dynamic_pointer_cast(node)) + logical_reduce->set_keep_dims(reduce_setup.keep_dims); + node->validate_and_infer_types(); + + const auto data_rank_value = reduce_setup.data_shape.size(); + + ngraph::Output output_shape; + if (reduce_setup.keep_dims) { + output_shape = std::make_shared( + dims, + ngraph::opset3::Constant::create(ngraph::element::i64, {reduce_setup.axes.size()}, reduce_setup.axes), + ngraph::opset3::Constant::create(ngraph::element::i64, {reduce_setup.gather_indices.size()}, reduce_setup.gather_indices), + ngraph::opset3::Constant::create(ngraph::element::i64, {1}, {0})); + } else { + output_shape = std::make_shared( + dims, + ngraph::opset3::Constant::create(ngraph::element::i64, {reduce_setup.gather_indices.size()}, reduce_setup.gather_indices), + ngraph::opset3::Constant::create(ngraph::element::i64, {1}, {0})); + } + const auto dsr1 = std::make_shared(node, output_shape); + return std::make_shared( + ngraph::NodeVector{dsr1}, + ngraph::ParameterVector{data, dims}, + "Expected"); + } +}; + +TEST_P(DynamicToStaticShapeReduce, CompareFunctions) { +} + +INSTANTIATE_TEST_CASE_P(Arithmetic, DynamicToStaticShapeReduce, arithmetic_combinations); +INSTANTIATE_TEST_CASE_P(Logical, DynamicToStaticShapeReduce, logical_combinations); + +} // namespace diff --git a/inference-engine/tests/functional/plugin/myriad/subgraph_tests/dsr_reduce.cpp b/inference-engine/tests/functional/plugin/myriad/subgraph_tests/dsr_reduce.cpp new file mode 100644 index 00000000000..f14307c0d29 --- /dev/null +++ b/inference-engine/tests/functional/plugin/myriad/subgraph_tests/dsr_reduce.cpp @@ -0,0 +1,110 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +namespace { + +using DataType = ngraph::element::Type_t; +using DataDims = ngraph::Shape; + +struct ReduceTestCase { + ngraph::Shape data_shape; + std::vector axes; + bool keep_dims; +}; + +const auto arithmetic_combinations = testing::Combine( + testing::Values( + ngraph::opset3::ReduceMax::type_info, + ngraph::opset3::ReduceMean::type_info, + ngraph::opset3::ReduceMin::type_info, + ngraph::opset3::ReduceProd::type_info, + ngraph::opset3::ReduceSum::type_info), + testing::Values( + ngraph::element::f16, + ngraph::element::f32, + ngraph::element::i32, + ngraph::element::i64, + ngraph::element::u8), + testing::Values( + ngraph::element::i32, + ngraph::element::i64, + ngraph::element::u8), + testing::Values( + // data_shape, axes, keep_dims + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, true}, + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, false}, + ReduceTestCase{{1, 3, 224, 224}, {0, 1, 2, 3}, true}, + ReduceTestCase{{1, 3, 224, 224}, {1, 3}, false}, + ReduceTestCase{{4}, {0}, true}), + testing::Values(CommonTestUtils::DEVICE_MYRIAD)); + +const auto logical_combinations = testing::Combine( + testing::Values( + ngraph::opset3::ReduceLogicalAnd::type_info, + ngraph::opset3::ReduceLogicalOr::type_info), + testing::Values(ngraph::element::boolean), + testing::Values( + ngraph::element::i32, + ngraph::element::i64, + ngraph::element::u8), + testing::Values( + // data_shape, axes, keep_dims + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, true}, + ReduceTestCase{{1, 3, 224, 224}, {2, 3}, false}, + ReduceTestCase{{1, 3, 224, 224}, {0, 1, 2, 3}, true}, + ReduceTestCase{{1, 3, 224, 224}, {1, 3}, false}, + ReduceTestCase{{4}, {0}, true}), + testing::Values(CommonTestUtils::DEVICE_MYRIAD)); + + +using Parameters = std::tuple< + ngraph::NodeTypeInfo, + DataType, + DataType, + ReduceTestCase, + LayerTestsUtils::TargetDevice +>; + +class DSR_Reduce : public testing::WithParamInterface, + public LayerTestsUtils::LayerTestsCommon { +protected: + void SetUp() override { + const auto& parameters = GetParam(); + const auto& reduce_type = std::get<0>(parameters); + const auto& data_type = std::get<1>(parameters); + const auto& axes_type = std::get<2>(parameters); + const auto& reduce_setup = std::get<3>(parameters); + targetDevice = std::get<4>(parameters); + + const auto data = std::make_shared(data_type, reduce_setup.data_shape); + const auto axes = ngraph::opset3::Constant::create(axes_type, {reduce_setup.axes.size()}, reduce_setup.axes); + + const auto dims = std::make_shared(ngraph::element::i64, ngraph::Shape{reduce_setup.data_shape.size()}); + + const auto dsr = std::make_shared(data, dims); + const auto node = ngraph::helpers::getNodeSharedPtr(reduce_type, {dsr, axes}); + + if (auto arithmetic_reduce = std::dynamic_pointer_cast(node)) + arithmetic_reduce->set_keep_dims(reduce_setup.keep_dims); + else if (auto logical_reduce = std::dynamic_pointer_cast(node)) + logical_reduce->set_keep_dims(reduce_setup.keep_dims); + node->validate_and_infer_types(); + const auto result = std::make_shared(node); + function = std::make_shared(ngraph::ResultVector{result}, + ngraph::ParameterVector{data, dims}, "DSR-Reduce"); + } +}; + +TEST_P(DSR_Reduce, CompareWithReference) { + Run(); +} + +INSTANTIATE_TEST_CASE_P(DISABLED_DynamicArithmeticReduce, DSR_Reduce, arithmetic_combinations); +INSTANTIATE_TEST_CASE_P(DISABLED_DynamicLogicalReduce, DSR_Reduce, logical_combinations); + +} // namespace diff --git a/ngraph/src/ngraph/validation_util.cpp b/ngraph/src/ngraph/validation_util.cpp index 87e6d918c32..ae6f2ac99ff 100644 --- a/ngraph/src/ngraph/validation_util.cpp +++ b/ngraph/src/ngraph/validation_util.cpp @@ -849,8 +849,11 @@ int64_t ngraph::normalize_axis(const std::string& node_description, } const auto tensor_rank_value = tensor_rank.get_length(); - return normalize_axis( - node_description, axis, tensor_rank_value, -tensor_rank_value, tensor_rank_value - 1); + return normalize_axis(node_description, + axis, + tensor_rank_value, + -tensor_rank_value, + tensor_rank_value ? (tensor_rank_value - 1) : 0); } int64_t ngraph::normalize_axis(const Node* node,