[IE][VPU]: Fixes addCopyForOutputsInsideNetwork (#2393)
* [IE][VPU]: Fixes addCopyForOutputsInsideNetwork In case of dynamic output with consumer pass tries to connect output's shape with new intermediate data twice: one at the moment of duplicateData call (successful) and once more at the end of the pass manually. The second try leads to error since child data is already connected. Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com> * [IE][VPU]: Introduces tests on addCopyForOutputsInsideNetwork Signed-off-by: Gladilov, Gleb <gleb.gladilov@intel.com>
This commit is contained in:
parent
cfb6fae2c9
commit
10df5907b5
@ -44,10 +44,6 @@ public:
|
||||
newIntermediateData,
|
||||
outputData,
|
||||
"addCopyForOutputsInsideNetwork");
|
||||
|
||||
if (const auto& parentShapeEdge = outputData->parentDataToShapeEdge()) {
|
||||
model->connectDataWithShape(parentShapeEdge->parent(), newIntermediateData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,13 @@ OutputInfo OutputInfo::fromNetwork(int ind) {
|
||||
return info;
|
||||
}
|
||||
|
||||
InputInfo InputInfo::constant(const DataDesc& desc) {
|
||||
InputInfo info;
|
||||
info.type = InputType::Constant;
|
||||
info.desc = desc;
|
||||
return info;
|
||||
}
|
||||
|
||||
OutputInfo OutputInfo::intermediate(const DataDesc& desc) {
|
||||
OutputInfo info;
|
||||
info.type = OutputType::Intermediate;
|
||||
@ -161,6 +168,8 @@ Stage TestModel::addStage(const std::vector<InputInfo>& curInputInfos, const std
|
||||
for (const auto& info : curInputInfos) {
|
||||
if (info.type == InputType::Original) {
|
||||
curInputs.push_back(_inputs.at(info.originalInputInd));
|
||||
} else if (info.type == InputType::Constant) {
|
||||
curInputs.push_back(_model->addConstData(formatString("Const {} / {}", _stages.size(), curInputs.size()), info.desc));
|
||||
} else {
|
||||
curInputs.push_back(_stages.at(info.prevStageInd)->output(info.prevStageOutputInd));
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ private:
|
||||
enum class InputType {
|
||||
Original,
|
||||
PrevStageOutput,
|
||||
Intermediate
|
||||
Intermediate,
|
||||
Constant
|
||||
};
|
||||
|
||||
struct InputInfo final {
|
||||
@ -54,10 +55,12 @@ struct InputInfo final {
|
||||
int originalInputInd = -1;
|
||||
int prevStageInd = -1;
|
||||
int prevStageOutputInd = -1;
|
||||
DataDesc desc = DataDesc();
|
||||
|
||||
static InputInfo fromNetwork(int ind = 0);
|
||||
|
||||
static InputInfo fromPrevStage(int ind, int outputInd = 0);
|
||||
static InputInfo constant(const DataDesc& desc);
|
||||
|
||||
InputInfo& output(int ind);
|
||||
};
|
||||
|
@ -0,0 +1,217 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "graph_transformer_tests.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
class AddCopyForOutputsInsideNetwork : public vpu::GraphTransformerTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ASSERT_NO_FATAL_FAILURE(GraphTransformerTest::SetUp());
|
||||
ASSERT_NO_FATAL_FAILURE(InitCompileEnv());
|
||||
ASSERT_NO_FATAL_FAILURE(InitPipeline());
|
||||
|
||||
m_testModel = CreateTestModel();
|
||||
}
|
||||
|
||||
void CheckOutputs(const vpu::DataMap<vpu::Data>& parentShapes = {}, const vpu::DataMap<vpu::DataVector>& childShapes = {}) {
|
||||
for (const auto& output : m_testModel.getOutputs()) {
|
||||
ASSERT_TRUE(output->consumerEdges().empty());
|
||||
ASSERT_TRUE((parentShapes.count(output) == 0 && output->parentDataToShapeEdge() == nullptr) ||
|
||||
(parentShapes.count(output) == 1 && output->parentDataToShapeEdge()->parent() == parentShapes.at(output)));
|
||||
ASSERT_FALSE((childShapes.count(output) == 0) ^ output->childDataToShapeEdges().empty());
|
||||
if (output->childDataToShapeEdges().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vpu::DataVector actualChildDataObjects;
|
||||
const auto& actualChildShapesEdges = output->childDataToShapeEdges();
|
||||
std::transform(actualChildShapesEdges.begin(), actualChildShapesEdges.end(), std::back_inserter(actualChildDataObjects),
|
||||
[](const vpu::DataToShapeAllocation& edge) { return edge->child(); });
|
||||
ASSERT_EQ(actualChildDataObjects, childShapes.at(output));
|
||||
}
|
||||
}
|
||||
|
||||
void Compile() {
|
||||
m_pipeline.run(m_testModel.getBaseModel());
|
||||
}
|
||||
|
||||
void InitPipeline() {
|
||||
m_pipeline = vpu::PassSet();
|
||||
m_pipeline.addPass(passManager->dumpModel("before-addCopyForOutputsInsideNetwork"));
|
||||
m_pipeline.addPass(passManager->addCopyForOutputsInsideNetwork());
|
||||
m_pipeline.addPass(passManager->dumpModel("after-addCopyForOutputsInsideNetwork"));
|
||||
}
|
||||
|
||||
protected:
|
||||
vpu::PassSet m_pipeline;
|
||||
vpu::TestModel m_testModel;
|
||||
|
||||
const vpu::DataDesc m_defaultDescriptor = {1};
|
||||
};
|
||||
|
||||
TEST_F(AddCopyForOutputsInsideNetwork, DynamicOutputWithoutConsumer) {
|
||||
m_testModel.createInputs({m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor});
|
||||
m_testModel.createOutputs({m_defaultDescriptor, m_defaultDescriptor});
|
||||
m_testModel.addStage({vpu::InputInfo::fromNetwork(0), vpu::InputInfo::fromNetwork(1)}, {vpu::OutputInfo::fromNetwork(0)});
|
||||
|
||||
auto shapeProducer = m_testModel.addStage(
|
||||
{vpu::InputInfo::fromPrevStage(0, 0), vpu::InputInfo::constant(m_defaultDescriptor)},
|
||||
{vpu::OutputInfo::intermediate(m_defaultDescriptor)});
|
||||
|
||||
m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromPrevStage(1, 0),
|
||||
vpu::InputInfo::fromNetwork(2),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::fromNetwork(3),
|
||||
},
|
||||
{vpu::OutputInfo::fromNetwork(1)});
|
||||
|
||||
ASSERT_NO_THROW(m_testModel.getBaseModel()->connectDataWithShape(shapeProducer->output(0), m_testModel.getOutputs().back()));
|
||||
ASSERT_NO_THROW(Compile());
|
||||
CheckOutputs({{m_testModel.getOutputs().back(), shapeProducer->output(0)}});
|
||||
}
|
||||
|
||||
TEST_F(AddCopyForOutputsInsideNetwork, StaticOutputWithConsumer) {
|
||||
m_testModel.createInputs({m_defaultDescriptor, m_defaultDescriptor});
|
||||
m_testModel.createOutputs({m_defaultDescriptor, m_defaultDescriptor});
|
||||
|
||||
m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromNetwork(0),
|
||||
vpu::InputInfo::fromNetwork(1),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor)
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::fromNetwork(0),
|
||||
vpu::OutputInfo::fromNetwork(1)});
|
||||
|
||||
const auto shapeProducer = m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromPrevStage(0, 0),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor)
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::intermediate(m_defaultDescriptor)
|
||||
});
|
||||
|
||||
m_testModel.getBaseModel()->connectDataWithShape(shapeProducer->output(0), m_testModel.getOutputs().back());
|
||||
|
||||
ASSERT_NO_THROW(Compile());
|
||||
CheckOutputs({{m_testModel.getOutputs().back(), shapeProducer->output(0)}});
|
||||
}
|
||||
|
||||
TEST_F(AddCopyForOutputsInsideNetwork, DynamicOutputWithConsumer) {
|
||||
m_testModel.createInputs({m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor});
|
||||
m_testModel.createOutputs({m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor});
|
||||
|
||||
m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromNetwork(0),
|
||||
vpu::InputInfo::fromNetwork(1),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor)
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::fromNetwork(0),
|
||||
vpu::OutputInfo::fromNetwork(1)});
|
||||
|
||||
const auto shapeProducer = m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromPrevStage(0, 0),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor)
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::intermediate(m_defaultDescriptor)
|
||||
});
|
||||
|
||||
m_testModel.getBaseModel()->connectDataWithShape(shapeProducer->output(0), m_testModel.getOutputs()[1]);
|
||||
|
||||
m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromNetwork(2),
|
||||
vpu::InputInfo::fromPrevStage(1, 0),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::fromPrevStage(0, 1),
|
||||
},
|
||||
{vpu::OutputInfo::fromNetwork(2)});
|
||||
|
||||
ASSERT_NO_THROW(Compile());
|
||||
CheckOutputs({{m_testModel.getOutputs()[1], shapeProducer->output(0)}});
|
||||
}
|
||||
|
||||
TEST_F(AddCopyForOutputsInsideNetwork, StaticOutputWithConsumerAndDynamicOutputWithConsumer) {
|
||||
m_testModel.createInputs({m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor});
|
||||
m_testModel.createOutputs({m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor, m_defaultDescriptor});
|
||||
|
||||
m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromNetwork(0),
|
||||
vpu::InputInfo::fromNetwork(1),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor)
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::fromNetwork(0),
|
||||
vpu::OutputInfo::fromNetwork(1)});
|
||||
|
||||
const auto shapeProducer_0 = m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromPrevStage(0, 0),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor)
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::intermediate(m_defaultDescriptor)
|
||||
});
|
||||
|
||||
m_testModel.getBaseModel()->connectDataWithShape(shapeProducer_0->output(0), m_testModel.getOutputs()[1]);
|
||||
|
||||
m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromNetwork(2),
|
||||
vpu::InputInfo::fromNetwork(3),
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::fromNetwork(3)
|
||||
});
|
||||
|
||||
const auto shapeProducer_1 = m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromPrevStage(2, 0),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor)
|
||||
},
|
||||
{
|
||||
vpu::OutputInfo::intermediate(m_defaultDescriptor)
|
||||
});
|
||||
|
||||
m_testModel.addStage(
|
||||
{
|
||||
vpu::InputInfo::fromPrevStage(3, 0),
|
||||
vpu::InputInfo::fromPrevStage(1, 0),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::constant(m_defaultDescriptor),
|
||||
vpu::InputInfo::fromPrevStage(0, 1),
|
||||
},
|
||||
{vpu::OutputInfo::fromNetwork(2)});
|
||||
|
||||
m_testModel.getBaseModel()->connectDataWithShape(shapeProducer_1->output(0), m_testModel.getOutputs()[2]);
|
||||
|
||||
ASSERT_NO_THROW(Compile());
|
||||
CheckOutputs({
|
||||
{m_testModel.getOutputs()[1], shapeProducer_0->output(0)},
|
||||
{m_testModel.getOutputs()[2], shapeProducer_1->output(0)}});
|
||||
}
|
||||
|
||||
} // namespace
|
Loading…
Reference in New Issue
Block a user