diff --git a/inference-engine/src/vpu/graph_transformer/include/vpu/middleend/pass_manager.hpp b/inference-engine/src/vpu/graph_transformer/include/vpu/middleend/pass_manager.hpp index 51b7c9ff939..b8819a40d0d 100644 --- a/inference-engine/src/vpu/graph_transformer/include/vpu/middleend/pass_manager.hpp +++ b/inference-engine/src/vpu/graph_transformer/include/vpu/middleend/pass_manager.hpp @@ -243,6 +243,8 @@ public: Pass::Ptr replaceGemmByConv(); + Pass::Ptr propagateDynamismToOutputs(); + protected: StageBuilder::Ptr _stageBuilder; BackEnd::Ptr _backEnd; diff --git a/inference-engine/src/vpu/graph_transformer/src/middleend/pass_manager.cpp b/inference-engine/src/vpu/graph_transformer/src/middleend/pass_manager.cpp index 5e35e7cea30..d2108ae4364 100644 --- a/inference-engine/src/vpu/graph_transformer/src/middleend/pass_manager.cpp +++ b/inference-engine/src/vpu/graph_transformer/src/middleend/pass_manager.cpp @@ -91,6 +91,14 @@ PassSet::Ptr PassManager::buildMiddleEnd() { // Convert shape notation // + + // MyriadInferRequest::GetResult expects output shape data object + // to be in IE notation in case of dynamic data object + // propagateDynamismToOutputs must be applied before convertShapeNotation + // to mark shape in IE notation, not MDK notation as output + ADD_PASS(propagateDynamismToOutputs); + ADD_DUMP_PASS("propagateDynamismToOutputs"); + ADD_PASS(convertShapeNotation); ADD_DUMP_PASS("convertShapeNotation"); diff --git a/inference-engine/src/vpu/graph_transformer/src/middleend/passes/propagate_dynamism_to_outputs.cpp b/inference-engine/src/vpu/graph_transformer/src/middleend/passes/propagate_dynamism_to_outputs.cpp new file mode 100644 index 00000000000..555eb842b59 --- /dev/null +++ b/inference-engine/src/vpu/graph_transformer/src/middleend/passes/propagate_dynamism_to_outputs.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "vpu/middleend/pass_manager.hpp" + +#include +#include + +namespace vpu { + +namespace { + +class PassImpl final : public Pass { +public: + explicit PassImpl(StageBuilder::Ptr stageBuilder) : _stageBuilder(std::move(stageBuilder)) {} + + void run(const Model& model) override { + for (const auto& data : model->datas()) { + if (data->usage() != DataUsage::Output || data->parentDataToShapeEdge() != nullptr) { + continue; + } + + const auto& producer = data->producer(); + VPU_THROW_UNLESS(producer, "Output data must have a producer, but {} doesn't have", data->name()); + + if (producer->type() != StageType::Convert) { + continue; + } + + VPU_THROW_UNLESS(producer->numInputs() == 1, + "Only single input producers are supported, but {} has {} inputs", + producer->name(), producer->numInputs()); + + const auto& input = producer->input(0); + const auto& parentDataToShapeEdge = input->parentDataToShapeEdge(); + if (parentDataToShapeEdge == nullptr) { + continue; + } + const auto parent = parentDataToShapeEdge->parent(); + + // MyriadInferRequest::GetResult assumes that dynamic data object has shape data object + // with the same name + suffix "@shape" + const auto shapeName = data->name() + "@shape"; + const auto& shapeOutput = model->addOutputData(shapeName, parent->desc()); + + if (parent->numConsumers() > 0) { + _stageBuilder->addCopyStage( + model, + "copy-for-dynamic-output", + nullptr, + parent, + shapeOutput, + "PropagateDynamismToOutput"); + + } else { + const auto parentProducerEdge = parent->producerEdge(); + VPU_THROW_UNLESS(parentProducerEdge != nullptr, + "Data containing shape is expected to have a producer, but {} doesn't have", parent->name()); + + for (const auto& dataToShapeEdge : parent->childDataToShapeEdges()) { + model->replaceDataToShapeParent(dataToShapeEdge, shapeOutput); + } + + model->replaceStageOutput(parentProducerEdge, shapeOutput); + model->removeUnusedData(parent); + } + + model->connectDataWithShape(shapeOutput, data); + } + } + +private: + StageBuilder::Ptr _stageBuilder; +}; + +} // namespace + +Pass::Ptr PassManager::propagateDynamismToOutputs() { + return std::make_shared(_stageBuilder); +} + +} // namespace vpu diff --git a/inference-engine/src/vpu/graph_transformer/src/stages/dynamic_shape_resolver.cpp b/inference-engine/src/vpu/graph_transformer/src/stages/dynamic_shape_resolver.cpp index 2c735b78ea5..3e7ac72b555 100644 --- a/inference-engine/src/vpu/graph_transformer/src/stages/dynamic_shape_resolver.cpp +++ b/inference-engine/src/vpu/graph_transformer/src/stages/dynamic_shape_resolver.cpp @@ -50,14 +50,13 @@ void FrontEnd::parseDSR(const Model& model, const ie::CNNLayerPtr& layer, const // Create the second output with shape in case of dynamic output const auto& shapeOutput = model->addOutputData(dataOutput->name() + "@shape", shape->desc()); - model->replaceStageOutput(shapeProducerEdge, shapeOutput); - model->connectDataWithShape(shapeOutput, dataOutput); - for (const auto& dataToShapeEdge : shape->childDataToShapeEdges()) { model->replaceDataToShapeParent(dataToShapeEdge, shapeOutput); } - + model->replaceStageOutput(shapeProducerEdge, shapeOutput); model->removeUnusedData(shape); + + model->connectDataWithShape(shapeOutput, dataOutput); } else { model->connectDataWithShape(shape, dataOutput); }