[IE][VPU][nGraph]: Enables dynamic Reshape with non-const pattern support in myriad plugin (#1159)

* [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>
This commit is contained in:
Gladilov, Gleb 2020-07-13 18:19:05 +03:00 committed by GitHub
parent 08d8d36667
commit 543559f58c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 337 additions and 164 deletions

View File

@ -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

View File

@ -8,9 +8,9 @@
namespace vpu {
class DynamicToStaticShapeShapeOf : public ngraph::pass::GraphRewrite {
class EliminateShapeOfAfterDSR : public ngraph::pass::GraphRewrite {
public:
DynamicToStaticShapeShapeOf();
EliminateShapeOfAfterDSR();
};
} //namespace vpu

View File

@ -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);

View File

@ -3,6 +3,7 @@
//
#include "vpu/ngraph/operations/static_shape_broadcast.hpp"
#include "vpu/ngraph/utilities.hpp"
#include "vpu/utils/error.hpp"
@ -11,61 +12,6 @@
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);
}
}

View File

@ -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

View 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);
}

View 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 outShapeDescriptor = reshape->get_argument(1);
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());
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));
}

View File

@ -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);
}

View File

@ -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>()};
}

View 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) {

View 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]);
}

View 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);

View File

@ -3,111 +3,132 @@
//
#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);
std::shared_ptr<const ngraph::Function> transform() const {
const auto dsr = generateInputSubgraph();
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);
const auto outShapeDescriptorParam = m_patternGenerator(dsr);
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 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}};
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);
std::shared_ptr<const ngraph::Function> reference() const {
const auto dsr0 = generateInputSubgraph();
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 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>(
inDataDimsParam, outShapeDescriptorParam, true);
const auto dsr1 = std::make_shared<ngraph::vpu::op::DynamicShapeResolver>(
reshape, outShapeOfReshape);
return std::make_shared<ngraph::Function>(
ngraph::NodeVector{dsr1},
ngraph::ParameterVector{inDataParam, inDataDimsParam},
"Expected");
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{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

View File

@ -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,

View File

@ -151,7 +151,7 @@ namespace ngraph
bool evaluate(const HostTensorVector& outputs,
const HostTensorVector& inputs) override;
private:
protected:
bool m_special_zero;
};
}

View File

@ -23,6 +23,15 @@
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, {})
{

View 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>{})