[IE][VPU]: Remove dataToShape edges from unsued data (#1213)

* Check equality of shape data for the replaced and replacement input/output data in the model
* Connect data with shape in duplicateData method
* Disconnect shape with data which is being removed as unsued.
* Check that disconnected shape still have child dataToShape edges or consumers
* Refactor cleanUp to use removeUnsuedData and not duplicate code
This commit is contained in:
Maksim Doronin 2020-07-09 19:21:18 +03:00 committed by GitHub
parent c0acbe06f7
commit 2537174a43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 113 additions and 53 deletions

View File

@ -162,6 +162,7 @@ public:
const Stage& newDependentStage);
void removeStageDependency(const StageDependency& edge);
void removeStageDependency(const Stage& stage, const Data& dependency);
//
// Stage <-> Stage edges

View File

@ -186,6 +186,10 @@ Data ModelObj::duplicateData(
newData->_desc = newDesc.numDims() != 0 ? newDesc : origData->desc();
newData->_model = this;
if (const auto& parentDataToShapeEdge = origData->parentDataToShapeEdge()) {
connectDataWithShape(parentDataToShapeEdge->parent(), newData);
}
if (newDataUsage == DataUsage::Const) {
const auto& content = newContent != nullptr ? newContent : origData->content();
const auto& desc = newDesc != DataDesc() ? newDesc : origData->desc();
@ -491,6 +495,27 @@ void ModelObj::replaceStageInput(
IE_ASSERT(edge->_parentEdge == nullptr);
IE_ASSERT(edge->_childEdge == nullptr);
//
// New and old dynamic data must have the same parent shape data
//
if (const auto& oldParentDataToShapeEdge = edge->input()->parentDataToShapeEdge()) {
const auto& newParentDataToShapeEdge = newInput->parentDataToShapeEdge();
VPU_THROW_UNLESS(newParentDataToShapeEdge != nullptr,
"Replaced input data with name {} from {} stage with name {} has parentDataToShapeEdge, "
"but new input data with name {} has no parentDataToShapeEdge",
edge->input()->name(), edge->consumer()->type(), edge->consumer()->name(), newInput->name());
VPU_THROW_UNLESS(newParentDataToShapeEdge->parent() == oldParentDataToShapeEdge->parent(),
"Replaced input data with name {} from {} stage with name {} and new input data with name must "
"have the same shape data",
edge->input()->name(), edge->consumer()->type(), edge->consumer()->name(), newInput->name());
} else {
VPU_THROW_UNLESS(newInput->parentDataToShapeEdge() == nullptr,
"Replaced input data with name {} from {} stage with name {} has not parentDataToShapeEdge, "
"but new input data with name {} has",
edge->input()->name(), edge->consumer()->type(), edge->consumer()->name(), newInput->name());
}
//
// Edge change affects the Stage order.
//
@ -583,6 +608,27 @@ void ModelObj::replaceStageOutput(
IE_ASSERT(edge->_parentEdge == nullptr);
IE_ASSERT(edge->_childEdge == nullptr);
//
// New and old dynamic data must have the same parent shape data
//
if (const auto& oldParentDataToShapeEdge = edge->output()->parentDataToShapeEdge()) {
const auto& newParentDataToShapeEdge = newOutput->parentDataToShapeEdge();
VPU_THROW_UNLESS(newParentDataToShapeEdge != nullptr,
"Replaced output data with name {} from {} stage with name {} has parentDataToShapeEdge, "
"but new output data with name {} has no parentDataToShapeEdge",
edge->output()->name(), edge->producer()->type(), edge->producer()->name(), newOutput->name());
VPU_THROW_UNLESS(newParentDataToShapeEdge->parent() == oldParentDataToShapeEdge->parent(),
"Replaced output data with name {} from {} stage with name {} and new output data with name must "
"have the same shape data",
edge->output()->name(), edge->producer()->type(), edge->producer()->name(), newOutput->name());
} else {
VPU_THROW_UNLESS(newOutput->parentDataToShapeEdge() == nullptr,
"Replaced output data with name {} from {} stage with name {} has not parentDataToShapeEdge, "
"but new output data with name {} has",
edge->output()->name(), edge->producer()->type(), edge->producer()->name(), newOutput->name());
}
//
// Edge change affects the Stage order.
//
@ -724,6 +770,19 @@ void ModelObj::removeStageDependency(const StageDependency& edge) {
_stageDependencyEdgePtrList.erase(edge->_ptrPosInModel);
}
void ModelObj::removeStageDependency(const Stage& stage, const Data& dependency) {
const auto& dependentStagesEdges = dependency->dependentStagesEdges();
const auto it = std::find_if(dependentStagesEdges.begin(), dependentStagesEdges.end(), [&stage](const StageDependency& edge) {
return edge->dependentStage() == stage;
});
if (it != dependentStagesEdges.end()) {
const auto stageDependencyEdge = *it;
removeStageDependency(stageDependencyEdge);
}
}
ModelObj::InjectStageHelper::~InjectStageHelper() {
//
// Check that `done` was called.
@ -1656,18 +1715,8 @@ void ModelObj::replaceDataToShapeParent(
newParent->_childDataToShapeEdges.push_back(edge);
const auto& childProducer = child->producer();
if (childProducer != nullptr) {
const auto& dependentStagesEdges = oldParent->dependentStagesEdges();
const auto it = std::find_if(dependentStagesEdges.begin(), dependentStagesEdges.end(), [&childProducer](const StageDependency& edge) {
return edge->dependentStage() == childProducer;
});
if (it != dependentStagesEdges.end()) {
const auto edge = *it;
removeStageDependency(edge);
}
removeStageDependency(childProducer, oldParent);
if (isStageDependencyNeeded(childProducer, newParent)) {
// Shape and data are produced from different stages, make sure that shape is calculated before data
@ -1692,18 +1741,8 @@ void ModelObj::replaceDataToShapeChild(
newChild->_parentDataToShapeEdge = edge;
const auto& oldChildProducer = oldChild->producer();
if (oldChildProducer != nullptr) {
const auto &dependentStagesEdges = parent->dependentStagesEdges();
const auto it = std::find_if(dependentStagesEdges.begin(), dependentStagesEdges.end(), [&oldChildProducer](const StageDependency &edge) {
return edge->dependentStage() == oldChildProducer;
});
if (it != dependentStagesEdges.end()) {
const auto edge = *it;
removeStageDependency(edge);
}
removeStageDependency(oldChildProducer, parent);
}
const auto& newChildProducer = newChild->producer();
@ -1792,18 +1831,8 @@ void ModelObj::disconnectDatas(const DataToShapeAllocation& edge) {
_shapeEdgePtrList.erase(edge->_ptrPosInModel);
const auto& childProducer = child->producer();
if (childProducer != nullptr) {
const auto &dependentStagesEdges = parent->dependentStagesEdges();
const auto it = std::find_if(dependentStagesEdges.begin(), dependentStagesEdges.end(), [&childProducer](const StageDependency &edge) {
return edge->dependentStage() == childProducer;
});
if (it != dependentStagesEdges.end()) {
const auto edge = *it;
removeStageDependency(edge);
}
removeStageDependency(childProducer, parent);
}
}
@ -1854,6 +1883,11 @@ void ModelObj::disconnectStage(const Stage& stage) {
//
for (const auto& outEdge : stage->_outputEdges) {
// Disconnect from dependency
if (const auto& dataToShapeEdge = outEdge->output()->parentDataToShapeEdge()) {
removeStageDependency(stage, dataToShapeEdge->parent());
}
// Disconnect from consumers
for (const auto& consumerEdge : outEdge->_output->_consumerEdges) {
auto it1 = consumerEdge->_consumer->_prevStages.find(outEdge->_producer);
IE_ASSERT(it1 != consumerEdge->_consumer->_prevStages.end());
@ -1908,14 +1942,10 @@ void ModelObj::removeStage(const Stage& stage) {
}
void ModelObj::cleanUp() {
bool needAllocatorPreprocess = false;
for (const auto& data : datas()) {
if (data->_usage == DataUsage::Input) {
if (data->childDataToShapeEdges().empty()) {
VPU_THROW_UNLESS(!data->_consumerEdges.empty(),
"Input data {} must have at least one consumers, but got zero.", data->name());
}
VPU_THROW_UNLESS(!data->_consumerEdges.empty() || !data->childDataToShapeEdges().empty(),
"Input data {} must either have at least one consumer (but got zero) or be a shape data.", data->name());
IE_ASSERT(data->_parentDataToDataEdge == nullptr);
} else if (data->_usage == DataUsage::Output) {
IE_ASSERT(data->_producerEdge != nullptr);
@ -1929,22 +1959,10 @@ void ModelObj::cleanUp() {
}
} else {
if (data->_consumerEdges.empty() && data->_producerEdge == nullptr) {
if (data->usage() != DataUsage::Intermediate &&
data->usage() != DataUsage::Temp) {
needAllocatorPreprocess = true;
}
_dataList.erase(data);
IE_ASSERT(data->_ptrPosInModel != _dataPtrList.end());
_dataPtrList.erase(data->_ptrPosInModel);
removeUnusedData(data);
}
}
}
if (needAllocatorPreprocess) {
_allocator.setNeedToAllocNonIntermData();
}
}
void ModelObj::buildStageOrder() const {
@ -2128,6 +2146,14 @@ void ModelObj::removeUnusedData(const Data& data) {
_allocator.setNeedToAllocNonIntermData();
}
if (const auto dataToShapeEdge = data->parentDataToShapeEdge()) {
const auto shape = dataToShapeEdge->parent();
disconnectDatas(dataToShapeEdge);
VPU_INTERNAL_CHECK(!shape->childDataToShapeEdges().empty() || !shape->consumerEdges().empty(),
"Removed unused data (with name {}) must have a shape data (with name {}) which is a shape "
"for other data or has consumer", data->name(), shape->name());
}
_dataList.erase(data);
_dataPtrList.erase(data->_ptrPosInModel);
}

View File

@ -403,4 +403,37 @@ TEST_F(StageDependencyEdgeProcessingTests, RemoveStageDependencyUpdatesNextPrevS
ASSERT_EQ(it, nextStages.end());
}
} // namespace vpu
TEST_F(StageDependencyEdgeProcessingTests, RemoveStageDependencyViaDataToShapeEdgeUpdatesNextPrevStages) {
//
// -> [Data] -> (Stage) -> [Output]
// [Input] -> (Stage) |
// -> [Data] ------------> (Stage) -> [Output]
//
const DataDesc desc{1};
_testModel.createInputs({desc});
_testModel.createOutputs({desc, desc});
_testModel.addStage({InputInfo::fromNetwork()}, {OutputInfo::intermediate(desc),
OutputInfo::intermediate(desc)});
auto dependentStage = _testModel.addStage({InputInfo::fromPrevStage(0).output(0)}, {OutputInfo::fromNetwork(0)});
auto dependencyProducer = _testModel.addStage({InputInfo::fromPrevStage(0).output(1)}, {OutputInfo::fromNetwork(1)});
auto model = _testModel.getBaseModel();
ASSERT_NO_THROW(model->addStageDependency(dependentStage, dependencyProducer->output(0)));
ASSERT_NO_THROW(model->removeStageDependency(dependentStage, dependencyProducer->output(0)));
const auto prevStages = dependentStage->prevStages();
const auto nextStages = dependencyProducer->prevStages();
auto it = std::find(prevStages.begin(), prevStages.end(), dependencyProducer);
ASSERT_EQ(it, prevStages.end());
it = std::find(nextStages.begin(), nextStages.end(), dependentStage);
ASSERT_EQ(it, nextStages.end());
}
} // namespace vpu