From a072c3b7b694833685cca108ff97860bb3ee178a Mon Sep 17 00:00:00 2001 From: Ilya Churaev Date: Wed, 26 Aug 2020 20:45:54 +0300 Subject: [PATCH] Fixed mean image support for IR v10 (#1926) * Fixed mean image support for IR v10 * Fixed comments --- .../src/readers/ir_reader/ie_ir_parser.cpp | 130 ++++++++++++++++++++- .../src/readers/ir_reader/ie_ir_parser.hpp | 2 + .../cnn_network/cnn_ngraph_impl_tests.cpp | 94 +++++++++++++++ 3 files changed, 225 insertions(+), 1 deletion(-) diff --git a/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp b/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp index 6a3b42c..e932634 100644 --- a/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp +++ b/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp @@ -196,7 +196,135 @@ std::shared_ptr V10Parser::parse(const pugi::xml_node& root, std::i result_nodes[0]->add_control_dependency(assign); } } - return CNNNetwork(function); + CNNNetwork net(function); + parsePreProcess(net, root, binStream); + return net; +} + +void V10Parser::parsePreProcess(CNNNetwork& network, const pugi::xml_node& root, std::istream& binStream) { + /* + + + // in case of array – ref to the .bin file + + + */ + + auto ppNode = root.child("pre-process"); + if (ppNode.empty()) { + return; + } + // find out to what input this belongs to + std::string inputName; + InputInfo::Ptr preProcessInput; + + inputName = GetStrAttr(ppNode, "reference-layer-name", ""); + inputName = ngraph::trim(inputName); + if (inputName.empty()) { + // fallback (old format), look for the picture in the inputs + InputsDataMap inputs = network.getInputsInfo(); + + if (inputs.empty()) THROW_IE_EXCEPTION << "network has no input"; + + for (auto i : inputs) { + if (i.second->getTensorDesc().getDims().size() == 4) { + preProcessInput = i.second; + break; + } + } + if (!preProcessInput) { + preProcessInput = inputs.begin()->second; + } + + inputName = preProcessInput->name(); + } else { + preProcessInput = network.getInputsInfo()[inputName]; + if (!preProcessInput) + THROW_IE_EXCEPTION << "pre-process name ref '" << inputName << "' refers to un-existing input"; + } + + // dims vector without batch size + SizeVector inputDims = preProcessInput->getTensorDesc().getDims(); + size_t noOfChannels = 0, width = 0, height = 0; + + if (inputDims.size() < 2) { + THROW_IE_EXCEPTION << "network did not define input dimensions properly"; + } else if (inputDims.size() == 2) { // NC + noOfChannels = inputDims[1]; + width = inputDims[1]; + height = inputDims[0]; + } else if (inputDims.size() == 3) { + width = inputDims[2]; + height = inputDims[1]; + noOfChannels = inputDims[0]; + } else if (inputDims.size() == 4) { + width = inputDims[3]; + height = inputDims[2]; + noOfChannels = inputDims[1]; + } else if (inputDims.size() == 5) { + width = inputDims[4]; + height = inputDims[3]; + noOfChannels = inputDims[2]; + } + + PreProcessInfo& pp = preProcessInput->getPreProcess(); + pp.init(noOfChannels); + + auto meanSegmentPrecision = GetPrecisionAttr(ppNode, "mean-precision", Precision::UNSPECIFIED); + if (!meanSegmentPrecision || meanSegmentPrecision == Precision::MIXED) + THROW_IE_EXCEPTION << "mean blob defined without specifying precision."; + + ResponseDesc resp; + InferenceEngine::PreProcessChannel::Ptr preProcessChannel; + + int lastChanNo = -1; + std::unordered_set idsForMeanImage; + + FOREACH_CHILD(chan, ppNode, "channel") { + int chanNo = GetIntAttr(chan, "id", lastChanNo + 1); + if (chanNo >= static_cast(noOfChannels) || chanNo < 0) { + THROW_IE_EXCEPTION << "Pre-process channel id invalid: " << chanNo; + } + lastChanNo = chanNo; + preProcessChannel = pp[chanNo]; + + auto meanNode = chan.child("mean"); + if (!meanNode.empty()) { + if (!meanNode.attribute("size")) { + THROW_IE_EXCEPTION << "mean should have the attribute: size"; + } + if (meanNode.attribute("size")) { + idsForMeanImage.insert(chanNo); + size_t size = static_cast(GetIntAttr(meanNode, "size")); + size_t offset = static_cast(GetIntAttr(meanNode, "offset")); + if (width * height * meanSegmentPrecision.size() != size) { + THROW_IE_EXCEPTION << "mean blob size mismatch expected input, got: " << size + << " extpecting " << width << " x " << height << " x " + << meanSegmentPrecision.size(); + } + preProcessChannel->meanData = make_blob_with_precision(TensorDesc(meanSegmentPrecision, {height, width}, Layout::HW)); + preProcessChannel->meanData->allocate(); + auto lockedMem = preProcessChannel->meanData->buffer(); + char* data = lockedMem.as(); + binStream.seekg(offset, std::ios::beg); + binStream.read(data, size); + } + } + } + + if (idsForMeanImage.size() == noOfChannels) { + pp.setVariant(MEAN_IMAGE); + } else if (idsForMeanImage.size() == 0) { + pp.setVariant(NONE); + } else { + std::string validMeanImageIds = ""; + for (auto id : idsForMeanImage) { + validMeanImageIds += std::to_string(id) + " "; + } + THROW_IE_EXCEPTION << "mean is not provided for all channels\n" + "Provided mean image for: " + << validMeanImageIds; + } } V10Parser::GenericLayerParams V10Parser::parseGenericParams(const pugi::xml_node& node) { diff --git a/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp b/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp index 9517150..bb03fca 100644 --- a/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp +++ b/inference-engine/src/readers/ir_reader/ie_ir_parser.hpp @@ -7,6 +7,7 @@ #ifdef IR_READER_V10 # include # include +# include #endif // IR_READER_V10 #include @@ -169,6 +170,7 @@ private: std::istream& binStream, const GenericLayerParams& params); GenericLayerParams parseGenericParams(const pugi::xml_node& node); + void parsePreProcess(CNNNetwork& network, const pugi::xml_node& root, std::istream& binStream); std::map portsToData; std::map layersParseInfo; diff --git a/inference-engine/tests/functional/inference_engine/cnn_network/cnn_ngraph_impl_tests.cpp b/inference-engine/tests/functional/inference_engine/cnn_network/cnn_ngraph_impl_tests.cpp index 11c68af..b5565b9 100644 --- a/inference-engine/tests/functional/inference_engine/cnn_network/cnn_ngraph_impl_tests.cpp +++ b/inference-engine/tests/functional/inference_engine/cnn_network/cnn_ngraph_impl_tests.cpp @@ -461,6 +461,100 @@ TEST(CNNNGraphImplTests, ReadFromCNNNetReader) { ASSERT_EQ(3, network.layerCount()); } +TEST(CNNNGraphImplTests, ReadMeanImageFromCNNNetReader) { + std::string model = R"V0G0N( + + + + + + + + + + + + + + + + + + 1 + 3 + 22 + 22 + + + + + + + 1 + 3 + 22 + 22 + + + + + 1 + 3 + 22 + 22 + + + + + + + 1 + 3 + 22 + 22 + + + + + + + + + +)V0G0N"; + InferenceEngine::Core core; + size_t hwSize = 22*22; + size_t dataSize = hwSize*3; + Blob::Ptr data = make_shared_blob(TensorDesc(Precision::FP32, {dataSize}, Layout::C)); + data->allocate(); + { + auto lockData = data->buffer(); + float *dataPtr = lockData.as(); + + for (size_t i = 0; i < dataSize; ++i) { + dataPtr[i] = i; + } + } + CNNNetwork network = core.ReadNetwork(model, data); + ASSERT_EQ(3, network.layerCount()); + auto inputInfo = network.getInputsInfo().begin()->second; + ASSERT_NE(inputInfo, nullptr); + auto preProc = inputInfo->getPreProcess(); + ASSERT_EQ(3, preProc.getNumberOfChannels()); + ASSERT_EQ(preProc.getMeanVariant(), MeanVariant::MEAN_IMAGE); + + for (size_t i = 0; i < preProc.getNumberOfChannels(); i++) { + auto chMeanImg = preProc[i]; + ASSERT_NE(chMeanImg, nullptr); + ASSERT_NE(chMeanImg->meanData, nullptr); + auto lockData = chMeanImg->meanData->cbuffer(); + auto *dataPtr = lockData.as(); + for (size_t j = 0; j < hwSize; j++) { + ASSERT_EQ(dataPtr[j], hwSize*i + j); + } + } +} + TEST(CNNNGraphImplTests, CanChangeInputPrecision) { std::shared_ptr ngraph; { -- 2.7.4