From: Gleb Kazantaev Date: Fri, 30 Oct 2020 04:24:37 +0000 (+0300) Subject: Fixed convertFunctionToCNNNetwork to support non unique names (#2864) X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=251429511da0d4777899d3830f102497eda35197;p=platform%2Fupstream%2Fdldt.git Fixed convertFunctionToCNNNetwork to support non unique names (#2864) * Unique names normalization during nGraph to CNNNetwork conversion * Added tests * Code refactoring --- diff --git a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp index 97fb7b7..1b1efd1 100644 --- a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp +++ b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp @@ -942,6 +942,54 @@ void convertFunctionToICNNNetwork(const std::shared_ptrget_ops(); bool keep_constants = keep_constant_inputs || ::ngraph::op::util::has_op_with_type<::ngraph::op::FakeQuantize>(graph); + std::unordered_map> unique_names; + auto can_change_name = [](const std::shared_ptr & node) -> bool { + if (ngraph::as_type_ptr(node) || + ngraph::as_type_ptr(node)) { + return false; + } + for (const auto & output : node->outputs()) { + for (const auto & consumer : output.get_target_inputs()) { + if (ngraph::is_type(consumer.get_node())) { + return false; + } + } + } + return true; + }; + + auto generate_unique_name = [&unique_names](std::string name) -> std::string { + size_t suffix = 1; + while(unique_names.count(name + "/" + std::to_string(suffix))) { + ++suffix; + } + return name + "/" + std::to_string(suffix); + }; + + // normalize nodes names to be unique + for (auto & node : nodes) { + // skip Result operations as they have the same friendly name as their parent + if (ngraph::is_type(node.get())) { + continue; + } + + auto & duplicate = unique_names[node->get_friendly_name()]; + if (!duplicate) { + duplicate = node; + continue; + } + + if (!can_change_name(duplicate) && !can_change_name(node)) { + THROW_IE_EXCEPTION << "Detected two output operations with the same name: " << duplicate << " and " << node; + } + + auto & renamed = can_change_name(duplicate) ? duplicate : node; + renamed->set_friendly_name(generate_unique_name(renamed->get_friendly_name())); + + unique_names[duplicate->get_friendly_name()] = duplicate; + unique_names[node->get_friendly_name()] = node; + } + // Create layers and output data for (const auto &layer : nodes) { if (isInternalLayer(layer, keep_constants)) continue; @@ -1090,7 +1138,8 @@ void convertFunctionToICNNNetwork(const std::shared_ptrgetLayerByName(layer->get_friendly_name().c_str(), cnnLayer, nullptr); - if (ret != OK) THROW_IE_EXCEPTION << "Cannot find layer with name: " << layer->get_friendly_name(); + if (ret != OK) + THROW_IE_EXCEPTION << "Cannot find layer with name: " << layer->get_friendly_name(); auto inIndex = layer->input(i).get_index(); if (cnnLayer->insData.size() <= (inIndex - count_of_skipped) || diff --git a/inference-engine/tests/functional/inference_engine/cnn_network/convert_ngraph_to_cnn_network_tests.cpp b/inference-engine/tests/functional/inference_engine/cnn_network/convert_ngraph_to_cnn_network_tests.cpp index bdb93cc..b21e946 100644 --- a/inference-engine/tests/functional/inference_engine/cnn_network/convert_ngraph_to_cnn_network_tests.cpp +++ b/inference-engine/tests/functional/inference_engine/cnn_network/convert_ngraph_to_cnn_network_tests.cpp @@ -236,4 +236,161 @@ TEST(ConvertFunctionToCNNNetworkTests, UnsupportedDynamicOps) { "v3::NonZero non_zero (relu[0]:f32?) -> (i64{?,?})\n" "v0::Result result (non_zero[0]:i64{?,?}) -> (i64{?,?})"))); } +} + +TEST(ConvertFunctionToCNNNetworkTests, NonUniqueNamesAllInternal) { + std::shared_ptr f(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 3}); + auto begin = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + auto end = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + end->set_friendly_name(begin->get_name()); + auto stride = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {1, 1}); + auto ss = std::make_shared( + input, + begin, + end, + stride, + std::vector{1, 1}, std::vector{1, 1}); + + f = std::make_shared(ngraph::NodeVector{ss}, ngraph::ParameterVector{input}); + } + + InferenceEngine::CNNNetwork nGraphImpl(f); + nGraphImpl = CNNNetwork(InferenceEngine::details::convertFunctionToICNNNetwork(f, nGraphImpl)); + ASSERT_EQ(nGraphImpl.layerCount(), 5); +} + +TEST(ConvertFunctionToCNNNetworkTests, NonUniqueNamesHasResult1) { + std::shared_ptr f(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 3}); + auto begin = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + auto end = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + end->set_friendly_name(begin->get_name()); + auto stride = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {1, 1}); + auto ss = std::make_shared( + input, + begin, + end, + stride, + std::vector{1, 1}, std::vector{1, 1}); + + f = std::make_shared(ngraph::NodeVector{ss, begin}, ngraph::ParameterVector{input}); + } + + InferenceEngine::CNNNetwork nGraphImpl(f); + nGraphImpl = CNNNetwork(InferenceEngine::details::convertFunctionToICNNNetwork(f, nGraphImpl)); + ASSERT_EQ(nGraphImpl.layerCount(), 5); +} + +TEST(ConvertFunctionToCNNNetworkTests, NonUniqueNamesHasResult2) { + std::shared_ptr f(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 3}); + auto begin = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + begin->set_friendly_name("const"); + auto end = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + end->set_friendly_name("const"); + auto stride = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {1, 1}); + stride->set_friendly_name("const"); + auto ss = std::make_shared( + input, + begin, + end, + stride, + std::vector{1, 1}, std::vector{1, 1}); + + f = std::make_shared(ngraph::NodeVector{ss, begin}, ngraph::ParameterVector{input}); + } + + InferenceEngine::CNNNetwork nGraphImpl(f); + nGraphImpl = CNNNetwork(InferenceEngine::details::convertFunctionToICNNNetwork(f, nGraphImpl)); + ASSERT_EQ(nGraphImpl.layerCount(), 5); +} + +TEST(ConvertFunctionToCNNNetworkTests, NonUniqueNamesHasResult3) { + std::shared_ptr f(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 3}); + auto begin = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + begin->set_friendly_name("const"); + auto end = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + end->set_friendly_name("const"); + auto stride = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {1, 1}); + stride->set_friendly_name("const"); + auto ss = std::make_shared( + input, + begin, + end, + stride, + std::vector{1, 1}, std::vector{1, 1}); + ss->set_friendly_name("node"); + auto squeeze = std::make_shared(ss, ngraph::opset1::Constant::create(ngraph::element::i64, {1}, {0})); + squeeze->set_friendly_name("node"); + f = std::make_shared(ngraph::NodeVector{squeeze, begin}, ngraph::ParameterVector{input}); + } + + InferenceEngine::CNNNetwork nGraphImpl(f); + nGraphImpl = CNNNetwork(InferenceEngine::details::convertFunctionToICNNNetwork(f, nGraphImpl)); + ASSERT_EQ(nGraphImpl.layerCount(), 7); + auto outputs_info = nGraphImpl.getOutputsInfo(); + ASSERT_TRUE(outputs_info.count("node")); + ASSERT_TRUE(outputs_info.count("const")); +} + +TEST(ConvertFunctionToCNNNetworkTests, NonUniqueNamesNegative) { + std::shared_ptr f(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 3}); + auto begin = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + begin->set_friendly_name("const"); + auto end = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + end->set_friendly_name("const"); + auto stride = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {1, 1}); + auto ss = std::make_shared( + input, + begin, + end, + stride, + std::vector{1, 1}, std::vector{1, 1}); + + f = std::make_shared(ngraph::NodeVector{ss, begin, end}, ngraph::ParameterVector{input}); + } + + InferenceEngine::CNNNetwork nGraphImpl(f); + try { + InferenceEngine::details::convertFunctionToICNNNetwork(f, nGraphImpl); + FAIL() << "InferenceEngineException must be thrown"; + } catch(InferenceEngine::details::InferenceEngineException & e) { + EXPECT_THAT(e.what(), testing::HasSubstr(std::string("Detected two output operations with the same name:"))); + } +} + +TEST(ConvertFunctionToCNNNetworkTests, NonUniqueNamesParametersNegative) { + std::shared_ptr f(nullptr); + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 3}); + input->set_friendly_name("param"); + auto begin = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + auto end = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {0, 0}); + auto stride = ngraph::opset1::Constant::create(ngraph::element::i64, {2}, {1, 1}); + auto ss = std::make_shared( + input, + begin, + end, + stride, + std::vector{1, 1}, std::vector{1, 1}); + auto input2 = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 3}); + auto concat = std::make_shared(ngraph::NodeVector{ss, input2}, 0); + + f = std::make_shared(ngraph::NodeVector{concat}, ngraph::ParameterVector{input, input2}); + + InferenceEngine::CNNNetwork nGraphImpl(f); + try { + input2->set_friendly_name("param"); + InferenceEngine::details::convertFunctionToICNNNetwork(f, nGraphImpl); + FAIL() << "InferenceEngineException must be thrown"; + } catch(InferenceEngine::details::InferenceEngineException & e) { + EXPECT_THAT(e.what(), testing::HasSubstr(std::string("Detected two output operations with the same name:"))); + } } \ No newline at end of file