[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 <gleb.gladilov@intel.com>

* [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 <gleb.gladilov@intel.com>

* [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 <gleb.gladilov@intel.com>
This commit is contained in:
Gladilov, Gleb 2020-06-03 11:43:19 +03:00 committed by GitHub
parent 447dd3570d
commit 4e0c7a217f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 4 deletions

View File

@ -243,6 +243,8 @@ public:
Pass::Ptr replaceGemmByConv(); Pass::Ptr replaceGemmByConv();
Pass::Ptr propagateDynamismToOutputs();
protected: protected:
StageBuilder::Ptr _stageBuilder; StageBuilder::Ptr _stageBuilder;
BackEnd::Ptr _backEnd; BackEnd::Ptr _backEnd;

View File

@ -91,6 +91,14 @@ PassSet::Ptr PassManager::buildMiddleEnd() {
// Convert shape notation // 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_PASS(convertShapeNotation);
ADD_DUMP_PASS("convertShapeNotation"); ADD_DUMP_PASS("convertShapeNotation");

View File

@ -0,0 +1,83 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "vpu/middleend/pass_manager.hpp"
#include <set>
#include <memory>
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<PassImpl>(_stageBuilder);
}
} // namespace vpu

View File

@ -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 // Create the second output with shape in case of dynamic output
const auto& shapeOutput = model->addOutputData(dataOutput->name() + "@shape", shape->desc()); const auto& shapeOutput = model->addOutputData(dataOutput->name() + "@shape", shape->desc());
model->replaceStageOutput(shapeProducerEdge, shapeOutput);
model->connectDataWithShape(shapeOutput, dataOutput);
for (const auto& dataToShapeEdge : shape->childDataToShapeEdges()) { for (const auto& dataToShapeEdge : shape->childDataToShapeEdges()) {
model->replaceDataToShapeParent(dataToShapeEdge, shapeOutput); model->replaceDataToShapeParent(dataToShapeEdge, shapeOutput);
} }
model->replaceStageOutput(shapeProducerEdge, shapeOutput);
model->removeUnusedData(shape); model->removeUnusedData(shape);
model->connectDataWithShape(shapeOutput, dataOutput);
} else { } else {
model->connectDataWithShape(shape, dataOutput); model->connectDataWithShape(shape, dataOutput);
} }