[IE][VPU][nGraph]: Enables dynamic Reshape with non-const pattern support in myriad...
authorGladilov, Gleb <gleb.gladilov@intel.com>
Mon, 13 Jul 2020 15:19:05 +0000 (18:19 +0300)
committerGitHub <noreply@github.com>
Mon, 13 Jul 2020 15:19:05 +0000 (18:19 +0300)
* [IE][nGraph]: Introduces PartialShape ctor from values vector

Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
* [IE][VPU][nGraph]: Moves evaluateTargetShape to common utilities

The same functionality - get upper-bound shape estimation for dynamic
input - is needed in dynamic Reshape along with dynamic Broadcast.
Return value type has been changed from PartialShape to vector<int64_t>.
The reason is Reshape encodes special values (0, -1) into input values
that define output shape. Representing those values (which upper-bound
provides evaluateTargetShape) as PartialShape leads to incorrect
representation vector with -1 as dynamic shape - which is not expected.

Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
* [IE][VPU][nGraph]: Introduces StaticShapeReshape

In comparison with original Reshape StaticShapeReshape propagates
upper-bound shape through a function in case of dynamic input. To do so,
shape inference method gets upper-bound shape from evaluateTargetShape,
decodes special values (0, -1) in it and then propagate the result.

Output shape processing happens only once, because if shape inference
were called after ShapeOf operations have been optimized out on dynamic
path, then evaluateTargetShape will require evaluate method for all
operations that appear in function before current Reshape. Since
evaluate method is implemented not for all operations it lead to
Faster-RCNN compilation error.

Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
* [IE][VPU][nGraph]: Updates Reshape DTS on StaticShapeReshape

In case of non-const Reshape input that defines output shape DTS uses
StaticShapeReshape which propagates upper-bound shape evaluated from
this input through a function.

Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
* [IE][VPU][nGraph][Tests]: Refactoring DTS Reshape tests

The only changes are:

* header files include reordering
* indentation/wrapping fixing

Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
* [IE][VPU][nGraph]: Moves ShapeOf transformation out of DTS scope

In comparison with DTS ShapeOf transformation needs to work on whole
function. Separating these 2 transformations makes testing easier since
now it's possible to call specific DTS without ShapeOf transformation
and vice versa.

Also DynamicToStaticShapeOf has been renamed into
EliminateShapeOfAfterDSR since transformation doesn't introduce new DSR
operations.

Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
* [VPU][Tests]: Introduces DTS Reshape tests with non-const pattern

New StaticShapeReshape constructor has been added as well, since test
fixture should create it from reshape parameters, not reshape itself.

Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
17 files changed:
inference-engine/src/vpu/common/include/vpu/ngraph/operations/static_shape_reshape.hpp [new file with mode: 0644]
inference-engine/src/vpu/common/include/vpu/ngraph/transformations/eliminate_shapeof_after_dsr.hpp [moved from inference-engine/src/vpu/common/include/vpu/ngraph/transformations/dynamic_to_static_shape_shapeof.hpp with 63% similarity]
inference-engine/src/vpu/common/include/vpu/ngraph/utilities.hpp [new file with mode: 0644]
inference-engine/src/vpu/common/src/ngraph/operations/static_shape_broadcast.cpp
inference-engine/src/vpu/common/src/ngraph/operations/static_shape_reshape.cpp [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_reshape.cpp
inference-engine/src/vpu/common/src/ngraph/transformations/eliminate_shapeof_after_dsr.cpp [moved from inference-engine/src/vpu/common/src/ngraph/transformations/dynamic_to_static_shape_shapeof.cpp with 86% similarity]
inference-engine/src/vpu/common/src/ngraph/utilities.cpp [new file with mode: 0644]
inference-engine/src/vpu/graph_transformer/src/frontend/frontend.cpp
inference-engine/src/vpu/graph_transformer/src/stages/reshape.cpp
inference-engine/src/vpu/myriad_plugin/myriad_plugin.cpp
inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_reshape.cpp
inference-engine/tests/functional/plugin/myriad/ngraph/transformations/eliminate_shapeof_after_dsr.cpp [moved from inference-engine/tests/functional/plugin/myriad/ngraph/transformations/dynamic_to_static_shape_shapeof.cpp with 84% similarity]
ngraph/src/ngraph/op/reshape.hpp
ngraph/src/ngraph/partial_shape.cpp
ngraph/src/ngraph/partial_shape.hpp

diff --git a/inference-engine/src/vpu/common/include/vpu/ngraph/operations/static_shape_reshape.hpp b/inference-engine/src/vpu/common/include/vpu/ngraph/operations/static_shape_reshape.hpp
new file mode 100644 (file)
index 0000000..00b390f
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include "ngraph/op/util/attr_types.hpp"
+#include "ngraph/node.hpp"
+#include <ngraph/opsets/opset3.hpp>
+
+#include <memory>
+#include <vector>
+
+namespace ngraph { namespace vpu { namespace op {
+
+class StaticShapeReshape : public ngraph::opset3::Reshape {
+public:
+    StaticShapeReshape(const Output<Node>& arg, const Output<Node>& pattern, bool special_zero);
+    explicit StaticShapeReshape(const std::shared_ptr<ngraph::opset3::Reshape>& reshape);
+
+    static constexpr NodeTypeInfo type_info{"StaticShapeReshape", 0};
+    const NodeTypeInfo& get_type_info() const override { return type_info; }
+
+    void validate_and_infer_types() override;
+};
+
+}  // namespace op
+}  // namespace vpu
+}  // namespace ngraph
diff --git a/inference-engine/src/vpu/common/include/vpu/ngraph/utilities.hpp b/inference-engine/src/vpu/common/include/vpu/ngraph/utilities.hpp
new file mode 100644 (file)
index 0000000..ffd6e80
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include "ngraph/node.hpp"
+
+std::vector<std::int64_t> evaluateTargetShape(const ngraph::Output<ngraph::Node>& value);
index aed6a2d..afdcf7a 100644 (file)
@@ -3,6 +3,7 @@
 //
 
 #include "vpu/ngraph/operations/static_shape_broadcast.hpp"
+#include "vpu/ngraph/utilities.hpp"
 
 #include "vpu/utils/error.hpp"
 
 
 namespace ngraph { namespace vpu { namespace op {
 
-namespace {
-
-HostTensorVector evaluateShapeOf(Node* node, const HostTensorVector&) {
-    auto shapeOf = as_type<opset3::ShapeOf>(node);
-    const auto inputValue = shapeOf->input_value(0);
-    const auto outputValue = shapeOf->output(0);
-    const auto inputTensors =
-            HostTensorVector{std::make_shared<runtime::HostTensor>(inputValue)};
-    const auto outputTensors =
-            HostTensorVector{std::make_shared<runtime::HostTensor>(outputValue)};
-
-    shapeOf->evaluate(outputTensors, inputTensors);
-    return outputTensors;
-}
-
-HostTensorVector evaluateConstant(Node* node, const HostTensorVector&) {
-    const auto constantNode = as_type<opset3::Constant>(node);
-    const auto constant = std::make_shared<opset3::Constant>(*constantNode);
-
-    const auto outputTensor = std::make_shared<runtime::HostTensor>(constant);
-
-    return {outputTensor};
-}
-
-HostTensorVector evaluateOp(Node* node, const HostTensorVector& inputTensors) {
-    HostTensorVector outputTensors;
-    for (const auto& output : node->outputs()) {
-        outputTensors.push_back(std::make_shared<HostTensor>(output));
-    }
-
-    node->evaluate(outputTensors, inputTensors);
-    return outputTensors;
-}
-
-PartialShape evaluateTargetShape(const Output<Node>& value) {
-    static Evaluator<HostTensorPtr>::op_handler_map handlers = {
-            {opset3::ShapeOf::type_info,  evaluateShapeOf},
-            {opset3::Constant::type_info, evaluateConstant},
-            {opset3::Gather::type_info,   evaluateOp},
-            {opset3::Concat::type_info,   evaluateOp}};
-    Evaluator<HostTensorPtr>::value_map value_map;
-    Evaluator<HostTensorPtr> evaluator(handlers, value_map);
-
-    const auto shapeTensor = evaluator.evaluate(value);
-    if (!shapeTensor || !shapeTensor->get_is_allocated()) {
-        return PartialShape::dynamic();
-    }
-    const auto shapeConstNode = std::make_shared<opset3::Constant>(shapeTensor);
-    const auto resultShape = Shape{shapeConstNode->cast_vector<size_t>()};
-
-    return resultShape;
-}
-
-}  // namespace
-
 constexpr NodeTypeInfo StaticShapeBroadcast::type_info;
 
 StaticShapeBroadcast::StaticShapeBroadcast(const Output<Node>& arg,
@@ -106,14 +52,20 @@ void StaticShapeBroadcast::validate_and_infer_types() {
         ::ngraph::op::util::BroadcastBase::validate_and_infer_types();
         // Try to evaluate output shape. After some transformations further, we may not be able
         // to evaluate the target shape again, then we will leave the evaluated shape unchanged.
-        // For example, DynamicToStaticShapeShapeOf remove ShapeOf and pass the second input of DSR.
-        const auto evaluatedTargetShape = evaluateTargetShape(input_value(1));
+        // For example, EliminateShapeOfAfterDSR remove ShapeOf and pass the second input of DSR.
+        const auto evaluatedDimensionValues = evaluateTargetShape(input_value(1));
+        NODE_VALIDATION_CHECK(this, !evaluatedDimensionValues.empty(), "StaticShapeBroadcast (", get_friendly_name(), ") can't evaluate output shape");
+
+        const auto evaluatedTargetShape = ngraph::PartialShape(evaluatedDimensionValues);
         if (evaluatedTargetShape.is_static()) {
             m_evaluatedOutputShape = evaluatedTargetShape;
         }
         NODE_VALIDATION_CHECK(this, m_evaluatedOutputShape.is_static(),
                               "StaticShapeBroadcast (", get_friendly_name(), ") ",
                               "can't evaluate output shape, got: ", m_evaluatedOutputShape);
+        NODE_VALIDATION_CHECK(this, m_evaluatedOutputShape.all_non_negative(),
+                              "StaticShapeBroadcast (", get_friendly_name(), ") ",
+                              "expects non-negative shape, got: ", m_evaluatedOutputShape);
         set_output_type(0, get_input_element_type(0), m_evaluatedOutputShape);
     }
 }
diff --git a/inference-engine/src/vpu/common/src/ngraph/operations/static_shape_reshape.cpp b/inference-engine/src/vpu/common/src/ngraph/operations/static_shape_reshape.cpp
new file mode 100644 (file)
index 0000000..682de1c
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <numeric>
+#include "vpu/ngraph/operations/static_shape_reshape.hpp"
+#include "vpu/ngraph/utilities.hpp"
+
+namespace ngraph { namespace vpu { namespace op {
+
+constexpr NodeTypeInfo StaticShapeReshape::type_info;
+
+StaticShapeReshape::StaticShapeReshape(const Output<Node>& arg, const Output<Node>& pattern, bool special_zero)
+    : ::ngraph::opset3::Reshape(arg, pattern, special_zero) {
+    constructor_validate_and_infer_types();
+}
+
+StaticShapeReshape::StaticShapeReshape(const std::shared_ptr<ngraph::opset3::Reshape>& reshape)
+    : StaticShapeReshape(reshape->get_argument(0), reshape->get_argument(1), reshape->get_special_zero()) {
+}
+
+void StaticShapeReshape::validate_and_infer_types() {
+    const auto& targetShape = input_value(1);
+    if (as_type_ptr<opset3::Constant>(targetShape.get_node_shared_ptr())) {
+        opset3::Reshape::validate_and_infer_types();
+        return;
+    }
+
+    NODE_VALIDATION_CHECK(this, get_input_element_type(1).is_integral_number(), "Pattern must be an integral number.");
+    NODE_VALIDATION_CHECK(this, get_input_partial_shape(1).rank().compatible(1), "Pattern must have rank 1, got ", get_input_partial_shape(1).rank(), ".");
+
+    set_input_is_relevant_to_shape(1);
+
+    NODE_VALIDATION_CHECK(this, get_input_partial_shape(0).is_static(), "StaticShapeReshape (", get_friendly_name(), ") ",
+                          "input#0 is expected to be of static shape, got: ", get_input_partial_shape(0));
+
+    if (get_output_partial_shape(0).is_static()) {
+        return;
+    }
+
+    const auto& inputShape = get_input_shape(0);
+
+    auto outputDimensionsValues = evaluateTargetShape(targetShape);
+    NODE_VALIDATION_CHECK(this, !outputDimensionsValues.empty(), "StaticShapeReshape (", get_friendly_name(), ") can't evaluate output shape");
+
+    for (std::size_t i = 0; i < outputDimensionsValues.size(); ++i) {
+        if (outputDimensionsValues[i] == 0 && m_special_zero) {
+            NODE_VALIDATION_CHECK(this, inputShape[i] <= static_cast<std::size_t>(std::numeric_limits<std::int64_t>::max()),
+                                  "StaticShapeReshape (", get_friendly_name(), ") out of range input shape dimension value: ", inputShape[i]);
+            outputDimensionsValues[i] = static_cast<std::int64_t>(inputShape[i]);
+        }
+    }
+
+    NODE_VALIDATION_CHECK(this, std::none_of(outputDimensionsValues.cbegin(), outputDimensionsValues.cend(),
+        [](std::int64_t dimension) { return dimension < -1; }), "Dim size cannot be less than -1, got ", ngraph::PartialShape(outputDimensionsValues));
+    const auto negativeDimsCount = std::count_if(outputDimensionsValues.cbegin(), outputDimensionsValues.cend(),
+        [](std::int64_t dimension) { return dimension == -1; });
+    NODE_VALIDATION_CHECK(this, negativeDimsCount <= 1, "More than one dimension has size of -1 (", negativeDimsCount, ")");
+
+    const auto& inputShapeVolume = shape_size(inputShape);
+    if (negativeDimsCount == 1) {
+        const auto& outputShapeVolume = std::abs(std::accumulate(
+            outputDimensionsValues.cbegin(),
+            outputDimensionsValues.cend(),
+            static_cast<std::int64_t>(1),
+            std::multiplies<std::int64_t>())); //shape_size(outputDimensionsValues);
+        NODE_VALIDATION_CHECK(this, inputShapeVolume % outputShapeVolume == 0, "StaticShapeReshape (", get_friendly_name(), ") ",
+                              "output shape volume does not evenly divide the input shape volume: input shape volume = ", inputShapeVolume, " output shape ",
+                              "volume = ", outputShapeVolume);
+        NODE_VALIDATION_CHECK(this, outputShapeVolume != 0, "StaticShapeReshape (", get_friendly_name(), ") ",
+                              "output shape volume is equal to 0");
+
+        const auto actualValue = inputShapeVolume / outputShapeVolume;
+        NODE_VALIDATION_CHECK(this, actualValue <= static_cast<std::size_t>(std::numeric_limits<std::int64_t>::max()),
+                              "StaticShapeReshape (", get_friendly_name(), ") out of range output shape dimension value: ", actualValue);
+        std::replace(outputDimensionsValues.begin(), outputDimensionsValues.end(),
+            static_cast<std::int64_t>(-1), static_cast<std::int64_t>(actualValue));
+    }
+
+    const auto& outputShape = ngraph::PartialShape(outputDimensionsValues);
+    NODE_VALIDATION_CHECK(this, inputShapeVolume == shape_size(outputDimensionsValues), "Requested output shape (upper-bound) ", outputShape,
+                          " is incompatible with input shape ", get_input_shape(0), " (upper-bound)");
+
+    set_output_type(0, get_input_element_type(0), outputShape);
+}
+
+}  // namespace op
+}  // namespace vpu
+}  // namespace ngraph
index 9c7aa5f..1813bab 100644 (file)
@@ -13,7 +13,6 @@
 #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_shapeof.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"
@@ -131,9 +130,6 @@ void DynamicToStaticShape::transform(std::shared_ptr<ngraph::Function> function)
         transformation->second(operation);
     }
 
-    // Should be executed after all dynamic-to-static transformations
-    DynamicToStaticShapeShapeOf().run_on_function(function);
-
     function->validate_nodes_and_infer_types();
     validateStaticShapes(*function);
 }
index cb144bb..e6255b2 100644 (file)
@@ -12,6 +12,7 @@
 #include "ngraph/opsets/opset3.hpp"
 
 #include <memory>
+#include <vpu/ngraph/operations/static_shape_reshape.hpp>
 
 namespace vpu {
 
@@ -21,19 +22,17 @@ void dynamicToStaticShapeReshape(std::shared_ptr<ngraph::Node> target) {
                      "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 outShapeDescriptor = target->get_argument(1);
-    VPU_THROW_UNLESS(ngraph::as_type_ptr<ngraph::opset3::Constant>(outShapeDescriptor),
-                     "DynamicToStaticShape transformation for {} of type {} expects {} as input with index {}",
-                     target->get_friendly_name(), target->get_type_info(), ngraph::opset3::Constant::type_info, 1);
-
     const auto reshape = std::dynamic_pointer_cast<ngraph::opset3::Reshape>(target);
-    const auto copied = reshape->clone_with_new_inputs(target->input_values());
-    const auto inDataShape = dsr->input(1).get_source_output();
+    const auto outShapeDescriptor = reshape->get_argument(1);
 
-    const auto outShapeOfReshape = std::make_shared<ngraph::vpu::op::OutShapeOfReshape>(
-            inDataShape, outShapeDescriptor, reshape->get_special_zero());
+    const auto replacement = ngraph::as_type_ptr<ngraph::opset3::Constant>(outShapeDescriptor)
+        ? reshape->clone_with_new_inputs(reshape->input_values())
+        : std::make_shared<ngraph::vpu::op::StaticShapeReshape>(reshape);
+
+    const auto inDataShape = dsr->input(1).get_source_output();
+    const auto outShapeOfReshape = std::make_shared<ngraph::vpu::op::OutShapeOfReshape>(inDataShape, outShapeDescriptor, reshape->get_special_zero());
 
-    auto outDSR = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(copied, outShapeOfReshape);
+    auto outDSR = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(replacement, outShapeOfReshape);
     outDSR->set_friendly_name(reshape->get_friendly_name());
     ngraph::replace_node(std::move(target), std::move(outDSR));
 }
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 //
 
-#include "vpu/ngraph/transformations/dynamic_to_static_shape_shapeof.hpp"
+#include "vpu/ngraph/transformations/eliminate_shapeof_after_dsr.hpp"
 
 #include <vpu/ngraph/operations/dynamic_shape_resolver.hpp>
 #include <vpu/utils/error.hpp>
@@ -11,7 +11,7 @@
 
 namespace vpu {
 
-DynamicToStaticShapeShapeOf::DynamicToStaticShapeShapeOf() : GraphRewrite() {
+EliminateShapeOfAfterDSR::EliminateShapeOfAfterDSR() : GraphRewrite() {
     // We don't set strict_mode when use pattern Matcher,
     // so we can set any type and shape for input.
     auto inputWithAnyTypeAndShape = std::make_shared<ngraph::pattern::op::Label>(
@@ -33,7 +33,7 @@ DynamicToStaticShapeShapeOf::DynamicToStaticShapeShapeOf() : GraphRewrite() {
         return true;
     };
 
-    auto m = std::make_shared<ngraph::pattern::Matcher>(shapeOfPattern, "DynamicToStaticShapeShapeOf");
+    auto m = std::make_shared<ngraph::pattern::Matcher>(shapeOfPattern, "EliminateShapeOfAfterDSR");
     this->add_matcher(m, callback, ngraph::pass::PassProperty::CHANGE_DYNAMIC_STATE);
 }
 
diff --git a/inference-engine/src/vpu/common/src/ngraph/utilities.cpp b/inference-engine/src/vpu/common/src/ngraph/utilities.cpp
new file mode 100644 (file)
index 0000000..d0a84b9
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "vpu/ngraph/utilities.hpp"
+
+#include "ngraph/opsets/opset3.hpp"
+#include "ngraph/evaluator.hpp"
+
+ngraph::HostTensorVector evaluateShapeOf(ngraph::Node* node, const ngraph::HostTensorVector&) {
+    auto shapeOf = ngraph::as_type<ngraph::opset3::ShapeOf>(node);
+    const auto inputValue = shapeOf->input_value(0);
+    const auto outputValue = shapeOf->output(0);
+    const auto inputTensors =
+        ngraph::HostTensorVector{std::make_shared<ngraph::runtime::HostTensor>(inputValue)};
+    const auto outputTensors =
+        ngraph::HostTensorVector{std::make_shared<ngraph::runtime::HostTensor>(outputValue)};
+
+    shapeOf->evaluate(outputTensors, inputTensors);
+    return outputTensors;
+}
+
+ngraph::HostTensorVector evaluateConstant(ngraph::Node* node, const ngraph::HostTensorVector&) {
+    const auto constantNode = ngraph::as_type<ngraph::opset3::Constant>(node);
+    const auto constant = std::make_shared<ngraph::opset3::Constant>(*constantNode);
+
+    const auto outputTensor = std::make_shared<ngraph::runtime::HostTensor>(constant);
+
+    return {outputTensor};
+}
+
+ngraph::HostTensorVector evaluateOp(ngraph::Node* node, const ngraph::HostTensorVector& inputTensors) {
+    ngraph::HostTensorVector outputTensors;
+    for (const auto& output : node->outputs()) {
+        outputTensors.push_back(std::make_shared<ngraph::HostTensor>(output));
+    }
+
+    node->evaluate(outputTensors, inputTensors);
+    return outputTensors;
+}
+
+std::vector<std::int64_t> evaluateTargetShape(const ngraph::Output<ngraph::Node>& value) {
+    static ngraph::Evaluator<ngraph::HostTensorPtr>::op_handler_map handlers = {
+        {ngraph::opset3::ShapeOf::type_info,  evaluateShapeOf},
+        {ngraph::opset3::Constant::type_info, evaluateConstant},
+        {ngraph::opset3::Gather::type_info,   evaluateOp},
+        {ngraph::opset3::Concat::type_info,   evaluateOp},
+        {ngraph::opset3::Reshape::type_info,  evaluateOp},
+        {ngraph::opset3::Multiply::type_info, evaluateOp},
+        {ngraph::opset3::Squeeze::type_info,  evaluateOp},
+    };
+    ngraph::Evaluator<ngraph::HostTensorPtr>::value_map value_map;
+    ngraph::Evaluator<ngraph::HostTensorPtr> evaluator(handlers, value_map);
+
+    const auto shapeTensor = evaluator.evaluate(value);
+    if (!shapeTensor || !shapeTensor->get_is_allocated()) {
+        return {};
+    }
+
+    const auto shapeConstNode = std::make_shared<ngraph::opset3::Constant>(shapeTensor);
+    return {shapeConstNode->cast_vector<std::int64_t>()};
+}
index 743524e..beeb422 100644 (file)
@@ -115,6 +115,7 @@ FrontEnd::FrontEnd(StageBuilder::Ptr stageBuilder)
         {"OutShapeOfReshape",                                  LAYER_PARSER(parseOutShapeOfReshape)},
         {"StaticShapeBroadcast",                               LAYER_PARSER(parseBroadcast)},
         {"StaticShapeNonMaxSuppression",                       LAYER_PARSER(parseStaticShapeNMS)},
+        {"StaticShapeReshape",                                 LAYER_PARSER(parseReshape)},
     }} {}
 
 ModelPtr FrontEnd::buildInitialModel(ie::ICNNNetwork& network) {
index ebb5ae6..8af2637 100644 (file)
@@ -61,9 +61,8 @@ private:
 }  // namespace
 
 void FrontEnd::parseReshape(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const {
-    VPU_THROW_UNLESS(inputs.size() == 1 || (inputs.size() == 2 && inputs[1]->usage() == DataUsage::Const),
+    VPU_THROW_UNLESS(inputs.size() == 1 || inputs.size() == 2,
         "%v of type %v is not supported with dynamic shape", layer->name, layer->type);
-    IE_ASSERT((inputs.size() == 1) || (inputs.size() == 2 && inputs[1]->usage() == DataUsage::Const));
     IE_ASSERT(outputs.size() == 1);
     _stageBuilder->addReshapeStage(model, layer->name, layer, inputs[0], outputs[0]);
 }
index 2b1f7b9..bc756d7 100644 (file)
@@ -19,6 +19,8 @@
 #include <transformations/common_optimizations/common_optimizations.hpp>
 
 #include "vpu/ngraph/transformations/dynamic_to_static_shape.hpp"
+#include "vpu/ngraph/transformations/eliminate_shapeof_after_dsr.hpp"
+
 #include "generic_ie.hpp"
 
 #include "myriad_plugin.h"
@@ -41,6 +43,7 @@ ExecutableNetworkInternal::Ptr Engine::LoadExeNetworkImpl(
         ngraph::op::GenericIE::DisableReshape noReshape(function);
         ngraph::pass::CommonOptimizations().run_on_function(function);
         vpu::DynamicToStaticShape().transform(function);
+        vpu::EliminateShapeOfAfterDSR().run_on_function(function);
     }
 
     return std::make_shared<ExecutableNetwork>(*clonedNetwork, _mvnc, _devicePool, parsedConfigCopy);
index ee14731..5eb10c6 100644 (file)
 //
 
 #include "vpu/ngraph/transformations/dynamic_to_static_shape_reshape.hpp"
+#include "vpu/ngraph/transformations/dynamic_to_static_shape.hpp"
 #include "vpu/ngraph/operations/out_shape_of_reshape.hpp"
 #include "vpu/ngraph/operations/dynamic_shape_resolver.hpp"
 
-#include <ngraph_functions/utils/ngraph_helpers.hpp>
-#include <ngraph/function.hpp>
-#include <ngraph/opsets/opset1.hpp>
+#include "ngraph_functions/utils/ngraph_helpers.hpp"
+#include "ngraph/opsets/opset3.hpp"
+#include "ngraph/function.hpp"
 
-#include <common_test_utils/test_common.hpp>
-#include <gtest/gtest.h>
+#include "common_test_utils/test_common.hpp"
+#include "gtest/gtest.h"
 
 #include <string>
 #include <memory>
 #include <map>
 #include <vector>
-#include <vpu/ngraph/transformations/dynamic_to_static_shape.hpp>
+#include <vpu/ngraph/operations/static_shape_reshape.hpp>
 
 namespace {
 
-using DataType  = ngraph::element::Type;
 using DataShape = ngraph::Shape;
-using TestParams = std::tuple<DataShape, DataType>;
+using DataType  = ngraph::element::Type;
+using ReshapePatternGenerator = std::function<std::shared_ptr<ngraph::op::Op>(std::shared_ptr<ngraph::vpu::op::DynamicShapeResolver>)>;
 
-class DynamicToStaticShapeReshapeTests
-        : public CommonTestUtils::TestsCommon,
-          public testing::WithParamInterface<TestParams> {
+using TestParams = std::tuple<DataShape, DataType, ReshapePatternGenerator>;
+
+class DynamicToStaticShapeReshapeTests : public CommonTestUtils::TestsCommon, public testing::WithParamInterface<TestParams> {
 public:
     void SetUp() override {
         const auto& parameters = GetParam();
-        const auto& inDataShape  = std::get<0>(parameters);
-        const auto& inDataType = std::get<1>(parameters);
+        m_inDataShape      = std::get<0>(parameters);
+        m_inDataType       = std::get<1>(parameters);
+        m_patternGenerator = std::get<2>(parameters);
 
-        ngraph::helpers::CompareFunctions(
-                *transform(inDataType, inDataShape),
-                *reference(inDataType, inDataShape));
+        const auto& actual = transform();
+        const auto& expected = reference();
+        ngraph::helpers::CompareFunctions(*actual, *expected);
     }
 
 protected:
-    std::shared_ptr<const ngraph::Function> transform(
-            const ngraph::element::Type& inDataType,
-            const ngraph::Shape& inDataShape) const {
-        const auto inDataParam = std::make_shared<ngraph::op::Parameter>(
-                inDataType, inDataShape);
-        const auto inDataDimsParam = std::make_shared<ngraph::op::Parameter>(
-                ngraph::element::i64, ngraph::Shape{inDataShape.size()});
-        const auto outShapeDescriptorParam = std::make_shared<ngraph::op::Constant>(
-                ngraph::element::i64, ngraph::Shape{inDataShape.size()}, inDataShape);
-
-        const auto dsr = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(
-                inDataParam, inDataDimsParam);
-        const auto reshape = std::make_shared<ngraph::op::v1::Reshape>(
-                dsr, outShapeDescriptorParam, true);
-
-        auto function = std::make_shared<ngraph::Function>(
-                ngraph::NodeVector{reshape},
-                ngraph::ParameterVector{inDataParam, inDataDimsParam},
-                "Actual");
-        reshape->set_output_type(0, dsr->get_input_element_type(0), ngraph::PartialShape::dynamic(
-                outShapeDescriptorParam->get_output_partial_shape(0).rank()));
-
-        const auto transformations = vpu::Transformations{{
-            ngraph::op::v1::Reshape::type_info, vpu::dynamicToStaticShapeReshape}};
+    std::shared_ptr<const ngraph::Function> transform() const {
+        const auto dsr = generateInputSubgraph();
+
+        const auto outShapeDescriptorParam = m_patternGenerator(dsr);
+        const auto reshape = std::make_shared<ngraph::op::v1::Reshape>(dsr, outShapeDescriptorParam, true);
+
+        const auto function = generateFunction(reshape, *dsr, "Actual");
+        reshape->set_output_type(
+            0,
+            dsr->get_input_element_type(0),
+            ngraph::PartialShape::dynamic(outShapeDescriptorParam->get_output_partial_shape(0).rank()));
+
+        const auto transformations = vpu::Transformations{{ngraph::op::v1::Reshape::type_info, vpu::dynamicToStaticShapeReshape}};
         vpu::DynamicToStaticShape(transformations).transform(function);
         return function;
     }
 
-    std::shared_ptr<const ngraph::Function> reference(
-            const ngraph::element::Type& inDataType,
-            const ngraph::Shape& inDataShape) const {
-        const auto inDataParam = std::make_shared<ngraph::op::Parameter>(
-                inDataType, inDataShape);
-        const auto inDataDimsParam = std::make_shared<ngraph::op::Parameter>(
-                ngraph::element::i64, ngraph::Shape{inDataShape.size()});
-        const auto outShapeDescriptorParam = std::make_shared<ngraph::op::Constant>(
-                ngraph::element::i64, ngraph::Shape{inDataShape.size()}, inDataShape);
-
-        const auto dsr0 = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(
-                inDataParam, inDataDimsParam);
-        const auto reshape = std::make_shared<ngraph::op::v1::Reshape>(
-                dsr0, outShapeDescriptorParam, true);
-
-        const auto outShapeOfReshape = std::make_shared<ngraph::vpu::op::OutShapeOfReshape>(
-                inDataDimsParam, outShapeDescriptorParam, true);
-        const auto dsr1 = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(
-                reshape, outShapeOfReshape);
+    std::shared_ptr<const ngraph::Function> reference() const {
+        const auto dsr0 = generateInputSubgraph();
+
+        const auto outShapeDescriptorParam = m_patternGenerator(dsr0);
+        const auto reshape = ngraph::as_type_ptr<ngraph::opset3::Constant>(outShapeDescriptorParam)
+            ? std::make_shared<ngraph::opset3::Reshape>(dsr0, outShapeDescriptorParam, true)
+            : std::make_shared<ngraph::vpu::op::StaticShapeReshape>(dsr0, outShapeDescriptorParam, true);
+
+        const auto outShapeOfReshape = std::make_shared<ngraph::vpu::op::OutShapeOfReshape>(dsr0->input_value(1), outShapeDescriptorParam, true);
+        const auto dsr1 = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(reshape, outShapeOfReshape);
+        return generateFunction(dsr1, *dsr0, "Expected");
+    }
+
+private:
+    std::shared_ptr<ngraph::vpu::op::DynamicShapeResolver> generateInputSubgraph() const {
+        const auto inDataParam = std::make_shared<ngraph::op::Parameter>(m_inDataType, m_inDataShape);
+        const auto inDataDimsParam = std::make_shared<ngraph::op::Parameter>(ngraph::element::i64, ngraph::Shape{m_inDataShape.size()});
+        return std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(inDataParam, inDataDimsParam);
+    }
+
+    static std::shared_ptr<ngraph::Function> generateFunction(std::shared_ptr<ngraph::op::Op> result, const ngraph::op::Op& input, const std::string& name) {
         return std::make_shared<ngraph::Function>(
-                ngraph::NodeVector{dsr1},
-                ngraph::ParameterVector{inDataParam, inDataDimsParam},
-                "Expected");
+            ngraph::NodeVector{std::move(result)},
+            ngraph::ParameterVector{
+                std::dynamic_pointer_cast<ngraph::opset3::Parameter>(input.get_input_node_shared_ptr(0)),
+                std::dynamic_pointer_cast<ngraph::opset3::Parameter>(input.get_input_node_shared_ptr(1))
+            },
+            name);
     }
+
+private:
+    DataShape m_inDataShape;
+    DataType m_inDataType;
+    ReshapePatternGenerator m_patternGenerator;
 };
 
-TEST_P(DynamicToStaticShapeReshapeTests, compareFunctions) {
+TEST_P(DynamicToStaticShapeReshapeTests, compareFunctions) {}
+
+std::shared_ptr<ngraph::op::Op> generateStaticReshapePattern(std::shared_ptr<ngraph::vpu::op::DynamicShapeResolver> dsr) {
+    const auto& inDataShape = dsr->input_value(0).get_shape();
+    std::vector<std::int64_t> pattern(inDataShape.rbegin(), inDataShape.rend());
+    return std::make_shared<ngraph::op::Constant>(ngraph::element::i64, ngraph::Shape{pattern.size()}, pattern);
+}
+
+std::shared_ptr<ngraph::op::Op> generateDynamicReshapePattern(std::shared_ptr<ngraph::vpu::op::DynamicShapeResolver> dsr) {
+    const auto shapeOf = std::make_shared<ngraph::opset3::ShapeOf>(std::move(dsr));
+    const auto axis    = ngraph::opset3::Constant::create(ngraph::element::i64, {1}, {0});
+    const auto indices = ngraph::opset3::Constant::create(ngraph::element::i64, {1}, {0});
+    return std::make_shared<ngraph::opset3::Concat>(
+        ngraph::OutputVector{
+            std::make_shared<ngraph::opset3::Gather>(shapeOf, indices, axis),
+            ngraph::opset3::Constant::create(ngraph::element::i64, {1}, {-1})},
+        0);
 }
 
 INSTANTIATE_TEST_CASE_P(NGraph, DynamicToStaticShapeReshapeTests, testing::Combine(
-        testing::Values(
-                DataShape{4, 1000},
-                DataShape{3, 128, 256},
-                DataShape{2, 3, 128, 256}),
-        testing::Values(
-                ngraph::element::f16,
-                ngraph::element::f32,
-                ngraph::element::i32,
-                ngraph::element::i64,
-                ngraph::element::u8)
+    testing::Values(
+        DataShape{4, 1000},
+        DataShape{3, 128, 256},
+        DataShape{2, 3, 128, 256},
+        DataShape{1000, 256, 7, 7}),
+    testing::Values(
+        ngraph::element::f16,
+        ngraph::element::f32,
+        ngraph::element::i32,
+        ngraph::element::i64,
+        ngraph::element::u8),
+    testing::Values(
+        generateStaticReshapePattern,
+        generateDynamicReshapePattern)
 ));
 
 }  // namespace
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 //
 
-#include "vpu/ngraph/transformations/dynamic_to_static_shape_shapeof.hpp"
+#include "vpu/ngraph/transformations/eliminate_shapeof_after_dsr.hpp"
 
 #include <vpu/ngraph/operations/dynamic_shape_resolver.hpp>
 #include <vpu/ngraph/transformations/dynamic_to_static_shape.hpp>
@@ -20,8 +20,8 @@ namespace {
 using TensorType  = ngraph::element::Type_t;
 using TensorShape = ngraph::Shape;
 
-class DynamicToStaticShapeShapeOfRemoveDSR : public CommonTestUtils::TestsCommon,
-                                             public testing::WithParamInterface<std::tuple<TensorType, TensorShape>> {
+class EliminateShapeOfAfterDSRTest : public CommonTestUtils::TestsCommon,
+                                     public testing::WithParamInterface<std::tuple<TensorType, TensorShape>> {
 public:
     void SetUp() override {
         const auto& parameters = GetParam();
@@ -47,7 +47,7 @@ protected:
                 ngraph::ParameterVector{data, shape},
                 "Actual");
 
-        vpu::DynamicToStaticShapeShapeOf().run_on_function(function);
+        vpu::EliminateShapeOfAfterDSR().run_on_function(function);
         return function;
     }
 
@@ -63,10 +63,10 @@ protected:
     }
 };
 
-TEST_P(DynamicToStaticShapeShapeOfRemoveDSR, CompareFunctions) {
+TEST_P(EliminateShapeOfAfterDSRTest, CompareFunctions) {
 }
 
-INSTANTIATE_TEST_CASE_P(NGraph, DynamicToStaticShapeShapeOfRemoveDSR, testing::Combine(
+INSTANTIATE_TEST_CASE_P(NGraph, EliminateShapeOfAfterDSRTest, testing::Combine(
         testing::Values(
                 ngraph::element::f16,
                 ngraph::element::f32,
@@ -80,8 +80,8 @@ INSTANTIATE_TEST_CASE_P(NGraph, DynamicToStaticShapeShapeOfRemoveDSR, testing::C
                 TensorShape{2, 3, 128, 256})
 ));
 
-class DynamicToStaticShapeShapeOfWithOutRemoveDSR : public CommonTestUtils::TestsCommon,
-                                             public testing::WithParamInterface<std::tuple<TensorType, TensorShape>> {
+class EliminateShapeOfAfterDSRWithoutOutputDSR : public CommonTestUtils::TestsCommon,
+                                                 public testing::WithParamInterface<std::tuple<TensorType, TensorShape>> {
 public:
     void SetUp() override {
         const auto& parameters = GetParam();
@@ -108,7 +108,7 @@ protected:
                 ngraph::ParameterVector{data, shape},
                 "Actual");
 
-        vpu::DynamicToStaticShapeShapeOf().run_on_function(function);
+        vpu::EliminateShapeOfAfterDSR().run_on_function(function);
         return function;
     }
 
@@ -126,10 +126,10 @@ protected:
     }
 };
 
-TEST_P(DynamicToStaticShapeShapeOfWithOutRemoveDSR, CompareFunctions) {
+TEST_P(EliminateShapeOfAfterDSRWithoutOutputDSR, CompareFunctions) {
 }
 
-INSTANTIATE_TEST_CASE_P(NGraph, DynamicToStaticShapeShapeOfWithOutRemoveDSR, testing::Combine(
+INSTANTIATE_TEST_CASE_P(NGraph, EliminateShapeOfAfterDSRWithoutOutputDSR, testing::Combine(
         testing::Values(
                 ngraph::element::f16,
                 ngraph::element::f32,
@@ -143,8 +143,8 @@ INSTANTIATE_TEST_CASE_P(NGraph, DynamicToStaticShapeShapeOfWithOutRemoveDSR, tes
                 TensorShape{2, 3, 128, 256})
 ));
 
-class DynamicToStaticShapeShapeOfKeepDSR : public CommonTestUtils::TestsCommon,
-                                         public testing::WithParamInterface<std::tuple<TensorType, TensorShape>> {
+class EliminateShapeOfAfterDSRKeepDSR : public CommonTestUtils::TestsCommon,
+                                        public testing::WithParamInterface<std::tuple<TensorType, TensorShape>> {
 public:
     void SetUp() override {
         const auto& parameters = GetParam();
@@ -172,7 +172,7 @@ protected:
                 ngraph::ParameterVector{data, shape},
                 "Actual");
 
-        vpu::DynamicToStaticShapeShapeOf().run_on_function(function);
+        vpu::EliminateShapeOfAfterDSR().run_on_function(function);
         return function;
     }
 
@@ -193,10 +193,10 @@ protected:
     }
 };
 
-TEST_P(DynamicToStaticShapeShapeOfKeepDSR, CompareFunctions) {
+TEST_P(EliminateShapeOfAfterDSRKeepDSR, CompareFunctions) {
 }
 
-INSTANTIATE_TEST_CASE_P(NGraph, DynamicToStaticShapeShapeOfKeepDSR, testing::Combine(
+INSTANTIATE_TEST_CASE_P(NGraph, EliminateShapeOfAfterDSRKeepDSR, testing::Combine(
         testing::Values(
                 ngraph::element::f16,
                 ngraph::element::f32,
index a68f439..fa1e970 100644 (file)
@@ -151,7 +151,7 @@ namespace ngraph
                 bool evaluate(const HostTensorVector& outputs,
                               const HostTensorVector& inputs) override;
 
-            private:
+            protected:
                 bool m_special_zero;
             };
         }
index b3a049a..e31afb0 100644 (file)
 
 using namespace ngraph;
 
+PartialShape::PartialShape(const std::vector<Dimension::value_type>& dimensions)
+    : m_rank_is_static(true)
+{
+    std::transform(dimensions.cbegin(),
+                   dimensions.cend(),
+                   std::back_inserter(m_dimensions),
+                   [](const Dimension::value_type& dimension) { return dimension; });
+}
+
 PartialShape::PartialShape(const Shape& shape)
     : PartialShape(true, {})
 {
index 78f34d6..e42b4f7 100644 (file)
@@ -68,6 +68,10 @@ namespace ngraph
         {
         }
 
+        /// \brief Constructs a PartialShape with static rank from a vector of dimensions values.
+        /// \param dimensions The Dimension values for the constructed shape.
+        PartialShape(const std::vector<Dimension::value_type>& dimensions);
+
         /// \brief Constructs a static PartialShape with zero rank (the shape of a scalar).
         PartialShape()
             : PartialShape(std::initializer_list<Dimension>{})