[IE][VPU]: Support DTS for Split (#2576)
authorAndrew Bakalin <andrew.bakalin@intel.com>
Wed, 14 Oct 2020 08:02:21 +0000 (11:02 +0300)
committerGitHub <noreply@github.com>
Wed, 14 Oct 2020 08:02:21 +0000 (11:02 +0300)
* [IE Tests] Remove unnecessary cout
* [VPU] Add DTS for split
* [VPU][Tests] Add tests

inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_split.hpp [new file with mode: 0644]
inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape.cpp
inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_split.cpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_split.cpp [new file with mode: 0644]
inference-engine/tests/functional/plugin/myriad/subgraph_tests/dsr_split.cpp [new file with mode: 0644]
inference-engine/tests/ie_test_utils/functional_test_utils/layer_test_utils.hpp

diff --git a/inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_split.hpp b/inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_split.hpp
new file mode 100644 (file)
index 0000000..54e6c57
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include "ngraph/node.hpp"
+
+namespace vpu {
+
+void dynamicToStaticShapeSplit(std::shared_ptr<ngraph::Node> target);
+
+}  // namespace vpu
index 1241838..9dbdc4a 100644 (file)
@@ -14,6 +14,7 @@
 #include "vpu/ngraph/transformations/dynamic_to_static_shape_reduce.hpp"
 #include "vpu/ngraph/transformations/dynamic_to_static_shape_reshape.hpp"
 #include "vpu/ngraph/transformations/dynamic_to_static_shape_roialign.hpp"
+#include "vpu/ngraph/transformations/dynamic_to_static_shape_split.hpp"
 #include "vpu/ngraph/transformations/dynamic_to_static_shape_squeeze.hpp"
 #include "vpu/ngraph/transformations/dynamic_to_static_shape_strided_slice.hpp"
 #include "vpu/ngraph/transformations/dynamic_to_static_shape_topk.hpp"
@@ -26,6 +27,7 @@
 #include "vpu/utils/error.hpp"
 
 #include "ngraph/opsets/opset3.hpp"
+#include "ngraph/opsets/opset5.hpp"
 #include "vpu/ngraph/operations/dynamic_non_max_suppression.hpp"
 
 namespace vpu {
@@ -104,6 +106,7 @@ const Transformations& getDefaultTransformations() {
         {ngraph::opset3::Reshape::type_info,                   dynamicToStaticShapeReshape},
         {ngraph::opset3::Broadcast::type_info,                 dynamicToStaticShapeBroadcast},
         {ngraph::opset3::MatMul::type_info,                    dynamicToStaticShapeMatMul},
+        {ngraph::opset5::Split::type_info,                     dynamicToStaticShapeSplit},
 
         // reduction
         {ngraph::opset3::ReduceLogicalAnd::type_info, dynamicToStaticShapeReduce},
diff --git a/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_split.cpp b/inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_split.cpp
new file mode 100644 (file)
index 0000000..a74dc25
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "vpu/ngraph/transformations/dynamic_to_static_shape_broadcast.hpp"
+
+#include "vpu/ngraph/operations/dynamic_shape_resolver.hpp"
+#include "vpu/ngraph/utilities.hpp"
+#include "vpu/utils/error.hpp"
+
+#include "ngraph/graph_util.hpp"
+#include "ngraph/opsets/opset5.hpp"
+#include "ngraph/validation_util.hpp"
+
+namespace vpu {
+
+void dynamicToStaticShapeSplit(std::shared_ptr<ngraph::Node> target) {
+    const auto split = ngraph::as_type_ptr<ngraph::opset5::Split>(target);
+    VPU_THROW_UNLESS(split,
+                     "dynamicToStaticShapeSplit transformation is not applicable for {}, "
+                     "it should be {} instead",
+                     target, ngraph::opset5::Split::type_info);
+
+    const auto numSplits = split->get_num_splits();
+
+    const auto dsr = ngraph::as_type_ptr<ngraph::vpu::op::DynamicShapeResolver>(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);
+
+    const auto dataShape = dsr->input_value(1).get_node_shared_ptr();
+    const auto dataShapeType = dataShape->get_element_type();
+    const auto axisNode = ngraph::as_type_ptr<ngraph::opset5::Constant>(target->input_value(1).get_node_shared_ptr());
+    VPU_THROW_UNLESS(axisNode, "dynamicToStaticShapeSplit transformation is not applicable for {}, dynamic axis is not supported", target);
+
+    const auto dataRank = target->get_input_partial_shape(0).rank();
+    VPU_THROW_UNLESS(dataRank.is_static(), "dynamicToStaticShapeSplit transformation for {} doesn't support dynamic rank", target);
+    const auto srcAxis = axisNode->cast_vector<int64_t>();
+    VPU_THROW_UNLESS(srcAxis.size() == 1,
+                     "dynamicToStaticShapeSplit transformation for {} failed: axis node is represented as {} values while 1 is expected",
+                     target, srcAxis.size());
+    const auto resultAxis = ngraph::normalize_axis(target->description(), axisNode->cast_vector<int64_t>()[0], dataRank);
+
+    const auto axisVector = ngraph::opset5::Constant::create(dataShapeType, {1}, {resultAxis});
+
+    const auto dimToSplitBy = std::make_shared<ngraph::opset5::Gather>(dataShape,
+                                                                       axisVector,
+                                                                       ngraph::opset5::Constant::create(dataShapeType, {1}, {0}));
+    const auto splittedDim = std::make_shared<ngraph::opset5::Divide>(dimToSplitBy,
+                                                                      ngraph::opset5::Constant::create(dataShapeType, {1}, {numSplits}));
+    const auto resultShape = std::make_shared<ngraph::opset5::ScatterElementsUpdate>(dataShape,
+                                                                                     axisVector,
+                                                                                     splittedDim,
+                                                                                     ngraph::opset5::Constant::create(dataShapeType, {1}, {0}));
+
+    const auto copied = target->clone_with_new_inputs(target->input_values());
+
+    for (size_t i = 0; i < copied->get_output_size(); i++) {
+        const auto outDSR = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(copied->output(i), resultShape);
+        outDSR->set_friendly_name(target->get_friendly_name() + "." + std::to_string(i));
+        target->output(i).replace(outDSR);
+    }
+}
+
+}  // namespace vpu
diff --git a/inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_split.cpp b/inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_split.cpp
new file mode 100644 (file)
index 0000000..7079e72
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vpu/ngraph/transformations/dynamic_to_static_shape_split.hpp>
+
+#include <vpu/ngraph/operations/dynamic_shape_resolver.hpp>
+#include <vpu/ngraph/transformations/dynamic_to_static_shape.hpp>
+#include <common_test_utils/test_common.hpp>
+
+#include <ngraph_functions/utils/ngraph_helpers.hpp>
+#include <ngraph/opsets/opset5.hpp>
+
+namespace {
+
+using DataType = ngraph::element::Type_t;
+using DataDims = ngraph::Shape;
+
+struct SplitTestCase {
+    ngraph::Shape dataShape;
+    int64_t axis, numSplits;
+};
+
+const auto combinations = testing::Combine(
+        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),
+        testing::Values(
+                SplitTestCase{{6}, 0, 2},
+                SplitTestCase{{6, 12, 10, 24}, 1, 4},
+                SplitTestCase{{6, 12}, 1, 6},
+                SplitTestCase{{6, 12, 10, 24}, 3, 4},
+                SplitTestCase{{6, 12, 10, 24}, -1, 4}));
+
+
+class DynamicToStaticShapeSplit : public CommonTestUtils::TestsCommon,
+                                  public testing::WithParamInterface<std::tuple<DataType, DataType, SplitTestCase>> {
+public:
+    void SetUp() override {
+        const auto& parameters = GetParam();
+        const auto& dataType = std::get<0>(parameters);
+        const auto& idxType = std::get<1>(parameters);
+        const auto& splitSetup = std::get<2>(parameters);
+
+        ngraph::helpers::CompareFunctions(*transform(dataType, idxType, splitSetup),
+                                          *reference(dataType, idxType, splitSetup));
+    }
+
+protected:
+std::shared_ptr<const ngraph::Function> transform(
+        const ngraph::element::Type_t& dataType,
+        const ngraph::element::Type_t& idxType,
+        const SplitTestCase& splitSetup) const {
+    const auto data = std::make_shared<ngraph::opset5::Parameter>(dataType, splitSetup.dataShape);
+    const auto axis = ngraph::opset5::Constant::create(idxType, {}, {splitSetup.axis});
+
+    const auto dims = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::i64, ngraph::Shape{splitSetup.dataShape.size()});
+
+    const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(data, dims);
+    const auto node = std::make_shared<ngraph::opset5::Split>(dsr, axis, splitSetup.numSplits);
+
+    // tests are capable to compare functions with one result only
+    const auto testsWa = std::make_shared<ngraph::opset5::Concat>(node->outputs(), splitSetup.axis);
+
+    auto outputShape = node->get_output_partial_shape(0);
+    const auto function = std::make_shared<ngraph::Function>(
+            ngraph::NodeVector{testsWa},
+            ngraph::ParameterVector{data, dims},
+            "Actual");
+    node->set_output_type(0, dsr->get_input_element_type(0), ngraph::PartialShape::dynamic(splitSetup.dataShape.size()));
+
+    const auto transformations = vpu::Transformations{{node->type_info, vpu::dynamicToStaticShapeSplit}};
+    vpu::DynamicToStaticShape(transformations).run_on_function(function);
+    return function;
+}
+
+std::shared_ptr<const ngraph::Function> reference(
+        const ngraph::element::Type_t& dataType,
+        const ngraph::element::Type_t& idxType,
+        const SplitTestCase& splitSetup) const {
+    const auto data = std::make_shared<ngraph::opset5::Parameter>(dataType, splitSetup.dataShape);
+    const auto axisScalar = ngraph::opset5::Constant::create(idxType, {}, std::vector<int64_t>{splitSetup.axis});
+    const auto axisVec = ngraph::opset5::Constant::create(idxType, {1}, std::vector<int64_t>{splitSetup.axis});
+
+    const auto dims = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::i64, ngraph::Shape{splitSetup.dataShape.size()});
+
+    const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(data, dims);
+    const auto node = std::make_shared<ngraph::opset5::Split>(dsr, axisScalar, splitSetup.numSplits);
+
+    const auto dimToSplitBy = std::make_shared<ngraph::opset5::Gather>(dims,
+                                                                       axisVec,
+                                                                       ngraph::opset5::Constant::create(dims->get_element_type(), {1}, {0}));
+    const auto splittedDim = std::make_shared<ngraph::opset5::Divide>(dimToSplitBy,
+                                                                      ngraph::opset5::Constant::create(dims->get_element_type(), {1}, {splitSetup.numSplits}));
+    const auto newShape = std::make_shared<ngraph::opset5::ScatterElementsUpdate>(dims,
+                                                                                  axisVec,
+                                                                                  splittedDim,
+                                                                                  ngraph::opset5::Constant::create(dims->get_element_type(), {1}, {0}));
+
+    ngraph::NodeVector results;
+    for (size_t i = 0; i < node->get_output_size(); i++) {
+        results.push_back(std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(node->output(i), newShape));
+    }
+
+    // tests are capable to compare functions with one result only
+    const auto testsWa = std::make_shared<ngraph::opset5::Concat>(results, splitSetup.axis);
+
+    return std::make_shared<ngraph::Function>(
+            testsWa,
+            ngraph::ParameterVector{data, dims},
+            "Expected");
+}
+};
+
+TEST_P(DynamicToStaticShapeSplit, CompareFunctions) {
+}
+
+INSTANTIATE_TEST_CASE_P(smoke_NGraph, DynamicToStaticShapeSplit, combinations);
+
+}  // namespace
diff --git a/inference-engine/tests/functional/plugin/myriad/subgraph_tests/dsr_split.cpp b/inference-engine/tests/functional/plugin/myriad/subgraph_tests/dsr_split.cpp
new file mode 100644 (file)
index 0000000..103a032
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "dsr_tests_common.hpp"
+
+namespace {
+
+using namespace LayerTestsUtils::vpu;
+
+struct SplitTestCase {
+    DataShapeWithUpperBound dataShapes;
+    int64_t axis, numSplits;
+};
+
+const auto combinations = testing::Combine(
+        testing::Values(
+                ngraph::element::f16),
+        testing::Values(
+                ngraph::element::i32),
+        testing::Values(
+                SplitTestCase{{{6, 12, 10}, {6, 12, 15}}, 1, 3},
+                SplitTestCase{{{6, 12, 10}, {9, 12, 10}}, 1, 3},
+                SplitTestCase{{{6, 12}, {10, 12}}, 1, 4},
+                SplitTestCase{{{6, 12, 10, 24}, {6, 12, 10, 50}}, 0, 6},
+                SplitTestCase{{{6, 12, 10, 24}, {6, 12, 10, 50}}, -3, 2},
+                SplitTestCase{{{1, 128, 4}, {1, 256, 4}}, 2, 4}),
+        testing::Values(CommonTestUtils::DEVICE_MYRIAD));
+
+
+using Parameters = std::tuple<
+        DataType,
+        DataType,
+        SplitTestCase,
+        LayerTestsUtils::TargetDevice
+>;
+
+class DSR_Split : public testing::WithParamInterface<Parameters>, public DSR_TestsCommon {
+protected:
+    std::shared_ptr<ngraph::Node> createTestedOp() override {
+        const auto& parameters = GetParam();
+        const auto& dataType = std::get<0>(parameters);
+        const auto& idxType = std::get<1>(parameters);
+        const auto& splitSetup = std::get<2>(parameters);
+        targetDevice = std::get<3>(parameters);
+
+        const auto inputSubgraph = createInputSubgraphWithDSR(dataType, splitSetup.dataShapes);
+
+        const auto axis = ngraph::opset5::Constant::create(idxType, {}, {splitSetup.axis});
+
+        return std::make_shared<ngraph::opset5::Split>(inputSubgraph, axis, splitSetup.numSplits);
+    }
+};
+
+TEST_P(DSR_Split, CompareWithReference) {
+    Run();
+}
+
+INSTANTIATE_TEST_CASE_P(smoke_DynamicSplit, DSR_Split, combinations);
+
+}  // namespace
index 0962d0e..813c531 100644 (file)
@@ -66,7 +66,6 @@ protected:
 
     template<class T>
     void Compare(const T *expected, const T *actual, std::size_t size, T threshold) {
-        std::cout << std::endl;
         for (std::size_t i = 0; i < size; ++i) {
             const auto &ref = expected[i];
             const auto &res = actual[i];