From 4e0c7a217f7c8183fd64b83f59a6faac1cf63bef Mon Sep 17 00:00:00 2001 From: "Gladilov, Gleb" Date: Wed, 3 Jun 2020 11:43:19 +0300 Subject: [PATCH] [IE][VPU]: Faster-RCNN fixes on myriad plugin side (#711) * [IE][VPU]: Enables pass for propagating dynamism to network outputs If network had dynamic output and then myriad Front-End inserted convert stage at the end (to convert FP16 -> FP32 - output precision) then dynamism would not be propagated - we have convert stage that has dynamic input, but static output. As a result, we have run-time error in Convert kernel: input and output shapes do not match. At the moment, pass supports only Convert stage as output stage over which we should propagate dynamism to outputs. Signed-off-by: Gladilov, Gleb * [IE][VPU]: Fixes parse DSR in case of output data Replacing stage output must be done after replacing data to shape parent, because the last one may access original parent producer, but after replacing stage output it'd not have one. Signed-off-by: Gladilov, Gleb * [IE][VPU]: Fixes MacOS build * [IE][VPU]: Fixes shape data naming convention Plugin part assumes that if there is dynamic data object, that's represented as 2 different data objects (data and shape), then shape data object has name = data object name + @shape suffix. Pass that creates new dynamic data object should respect that assumption. * [IE][VPU]: Fixes dis-alignment in names of data objects representing dynamic data object MyriadInferRequest::GetResult assumes that in case of dynamic data object "data" data object and "shape" data object will have aligned names: "shape" name = "data" name + "@shape" suffix. In order to meet that expectation propagating dynamism pass must use output data object name as prefix. Additionally, propagating pass must be applied before converting shape notation pass in order to make output shape in IE notation, not MDK, as MyriadInferRequest::GetResult is expecting. Signed-off-by: Gladilov, Gleb --- .../include/vpu/middleend/pass_manager.hpp | 2 + .../src/middleend/pass_manager.cpp | 8 ++ .../passes/propagate_dynamism_to_outputs.cpp | 83 +++++++++++++++++++ .../src/stages/dynamic_shape_resolver.cpp | 7 +- 4 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 inference-engine/src/vpu/graph_transformer/src/middleend/passes/propagate_dynamism_to_outputs.cpp 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); }