1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
6 #include <unordered_set>
7 #include "ie_format_parser.h"
8 #include "ie_layer_parsers.h"
9 #include "xml_parse_utils.h"
10 #include "ie_blob_proxy.hpp"
11 #include "range_iterator.hpp"
14 #include "ie_icnn_network_stats.hpp"
16 using namespace InferenceEngine;
17 using namespace InferenceEngine::details;
18 using namespace XMLParseUtils;
21 void LayerParseParameters::addOutputPort(const LayerPortData &port) {
22 outputPorts.insert(std::upper_bound(outputPorts.begin(), outputPorts.end(), port,
23 [=](const LayerParseParameters::LayerPortData &lhs,
24 const LayerParseParameters::LayerPortData &rhs) {
25 return lhs.portId < rhs.portId;
30 void LayerParseParameters::addInputPort(const LayerPortData &port) {
31 inputPorts.insert(std::upper_bound(inputPorts.begin(), inputPorts.end(), port,
32 [=](const LayerParseParameters::LayerPortData &lhs,
33 const LayerParseParameters::LayerPortData &rhs) {
34 return lhs.portId < rhs.portId;
38 inline void ParseSegment(LayerParseParameters& prms, const pugi::xml_node &blob) {
39 uint64_t size = GetUInt64Attr(blob, "size", 0);
40 uint64_t start = GetUInt64Attr(blob, "offset", 0);
44 WeightSegment& segment = prms.blobs[blob.name()];
45 segment.start = static_cast<size_t>(start);
46 segment.size = static_cast<size_t>(size);
47 const std::string &preStr = GetStrAttr(blob, "precision", "");
49 segment.precision = Precision::FromStr(preStr);
51 segment.precision = prms.prms.precision;
54 int BaseCreator::version_ = 4;
56 void FormatParser::ParsePort(LayerParseParameters::LayerPortData& port, pugi::xml_node &node) const {
57 port.portId = GetIntAttr(node, "id");
58 ParseDims(port.dims, node);
59 const std::string &preStr = GetStrAttr(node, "precision", "");
60 if (!preStr.empty()) port.precision = Precision::FromStr(preStr);
63 void FormatParser::ParseGenericParams(pugi::xml_node& node, LayerParseParameters& layerParsePrms) const {
64 layerParsePrms.layerId = GetIntAttr(node, "id");
65 layerParsePrms.underIRVersion = _version;
67 InferenceEngine::LayerParams& prms = layerParsePrms.prms;
68 prms.type = XMLParseUtils::GetStrAttr(node, "type");
69 prms.precision = _defPrecision;
71 prms.name = GetStrAttr(node, "name");
72 const std::string& preStr = GetStrAttr(node, "precision", "");
74 prms.precision = Precision::FromStr(preStr);
76 if (prms.precision == Precision::MIXED) {
77 THROW_IE_EXCEPTION << "Layer precision must not be MIXED, at layer name: " << prms.name << ", offset: "
78 << node.offset_debug();
81 auto outNode = node.child("output");
82 if (!outNode.empty()) {
83 FOREACH_CHILD(_cn, outNode, "port") {
84 LayerParseParameters::LayerPortData port;
85 port.precision = prms.precision;
87 layerParsePrms.addOutputPort(port);
90 auto inpNode = node.child("input");
91 if (!inpNode.empty()) {
92 FOREACH_CHILD(_cn, inpNode, "port") {
93 LayerParseParameters::LayerPortData port;
94 port.precision = prms.precision;
96 layerParsePrms.addInputPort(port);
99 auto blob = node.child("biases");
101 ParseSegment(layerParsePrms, blob);
103 blob = node.child("weights");
105 ParseSegment(layerParsePrms, blob);
107 auto blobs = node.child("blobs");
108 if (!blobs.empty()) {
109 for (blob = blobs.first_child(); !blob.empty(); blob = blob.next_sibling()) {
110 ParseSegment(layerParsePrms, blob);
115 static inline std::string gen_id(int layer_id, int port_id) {
116 return (std::to_string(layer_id) + '.' + std::to_string(port_id));
119 InferenceEngine::CNNLayer::Ptr FormatParser::CreateLayer(pugi::xml_node& node,
120 LayerParseParameters& layerParsePrms) const {
121 for (auto &creator : getCreators()) {
122 if (!creator->shouldCreate(layerParsePrms.prms.type))
124 return creator->CreateLayer(node, layerParsePrms);
126 static LayerCreator<GenericLayer> genericCreator("");
127 return genericCreator.CreateLayer(node, layerParsePrms);
130 void FormatParser::SetLayerInput(CNNNetworkImpl& network, const std::string& dataId,
131 CNNLayerPtr& targetLayer, int inputPort) {
132 DataPtr& dataPtr = _portsToData[dataId];
133 if (!dataPtr) THROW_IE_EXCEPTION << "in Layer " << targetLayer->name
134 << ": trying to connect an edge to non existing output port: " << dataId;
136 dataPtr->getInputTo()[targetLayer->name] = targetLayer;
137 const LayerParseParameters& parseInfo = layersParseInfo[targetLayer->name];
138 if (targetLayer->insData.empty()) {
139 targetLayer->insData.resize(parseInfo.inputPorts.size());
141 for (unsigned i = 0; i < parseInfo.inputPorts.size(); i++) {
142 if (parseInfo.inputPorts[i].portId != inputPort) continue;
143 if (parseInfo.inputPorts[i].precision != dataPtr->getPrecision()) {
144 if (dataPtr->getPrecision() == Precision::UNSPECIFIED) {
145 dataPtr->setPrecision(parseInfo.inputPorts[i].precision);
147 // TODO: Make a correct exception
149 /*THROW_IE_EXCEPTION << "in Layer " << targetLayer->name
150 << ": trying to connect an edge to mismatch precision of output port: "
151 << dataPtr->getName();*/
154 if (!equal(parseInfo.inputPorts[i].dims, dataPtr->getDims()))
155 THROW_IE_EXCEPTION << "in Layer " << targetLayer->name
156 << ": trying to connect an edge to mismatch dimensions of output port: "
157 << dataPtr->getName()
158 << " dims input: " << dumpVec(parseInfo.inputPorts[i].dims)
159 << " dims output: " << dumpVec(dataPtr->getDims());
160 targetLayer->insData[i] = dataPtr;
161 const auto insId = gen_id(parseInfo.layerId, parseInfo.inputPorts[i].portId);
162 _portsToData[insId] = dataPtr;
165 THROW_IE_EXCEPTION << "input port " << inputPort << " does not exist in layer " << targetLayer->name;
168 FormatParser::FormatParser(int version): _version(version) {
169 BaseCreator::version_ = version;
172 CNNNetworkImplPtr FormatParser::Parse(pugi::xml_node& root) {
173 _network.reset(new CNNNetworkImpl());
174 _network->setName(GetStrAttr(root, "name", ""));
175 _defPrecision = Precision::FromStr(GetStrAttr(root, "precision", "UNSPECIFIED"));
176 _network->setPrecision(_defPrecision);
177 // parse the input Data
180 inputData = ParseInputData(root);
181 _portsToData[inputData->getName()] = inputData; // hack as this input does not have ports ids
182 InputInfo::Ptr info(new InputInfo());
183 info->setInputData(inputData);
184 _network->setInputInfo(info);
187 // parse the graph layers
188 auto allLayersNode = root.child("layers");
189 std::vector< CNNLayer::Ptr> inputLayers;
191 std::map<int, CNNLayer::Ptr> layerById;
192 bool identifyNetworkPrecision = _defPrecision == Precision::UNSPECIFIED;
193 for (auto node = allLayersNode.child("layer"); !node.empty(); node = node.next_sibling("layer")) {
194 LayerParseParameters lprms;
195 ParseGenericParams(node, lprms);
197 CNNLayer::Ptr layer = CreateLayer(node, lprms);
198 if (!layer) THROW_IE_EXCEPTION << "Don't know how to create Layer type: " << lprms.prms.type;
200 layersParseInfo[layer->name] = lprms;
201 _network->addLayer(layer);
202 layerById[lprms.layerId] = layer;
204 if (equal(layer->type, "input")) {
205 inputLayers.push_back(layer);
208 if (identifyNetworkPrecision) {
209 if (!_network->getPrecision()) {
210 _network->setPrecision(lprms.prms.precision);
212 if (_network->getPrecision() != lprms.prms.precision) {
213 _network->setPrecision(Precision::MIXED);
214 identifyNetworkPrecision = false;
218 for (int i = 0; i < lprms.outputPorts.size(); i++) {
219 const auto &outPort = lprms.outputPorts[i];
220 const auto outId = gen_id(lprms.layerId, outPort.portId);
221 const std::string outName = lprms.outputPorts.size() == 1
223 : lprms.prms.name + "." + std::to_string(i);
224 DataPtr& ptr = _network->getData(outName.c_str());
226 ptr.reset(new Data(outName, outPort.dims, outPort.precision, TensorDesc::getLayoutByDims(outPort.dims)));
227 ptr->setDims(outPort.dims);
229 _portsToData[outId] = ptr;
231 if (ptr->getCreatorLayer().lock())
232 THROW_IE_EXCEPTION << "two layers set to the same output [" << outName << "], conflict at offset "
233 << node.offset_debug();
235 ptr->getCreatorLayer() = layer;
236 layer->outData.push_back(ptr);
242 pugi::xml_node edges = root.child("edges");
244 FOREACH_CHILD(_ec, edges, "edge") {
245 int fromLayer = GetIntAttr(_ec, "from-layer");
246 int fromPort = GetIntAttr(_ec, "from-port");
247 int toLayer = GetIntAttr(_ec, "to-layer");
248 int toPort = GetIntAttr(_ec, "to-port");
250 const auto dataId = gen_id(fromLayer, fromPort);
251 auto targetLayer = layerById[toLayer];
253 THROW_IE_EXCEPTION << "Layer ID " << toLayer << " was not found while connecting edge at offset "
254 << _ec.offset_debug();
256 SetLayerInput(*_network, dataId, targetLayer, toPort);
260 // a hacK: set input to the first layer that is not connected...
261 bool inputWasSet = false;
262 for (auto& kvp : layerById) {
263 CNNLayer::Ptr& layer = kvp.second;
264 const LayerParseParameters& parseInfo = layersParseInfo[layer->name];
265 size_t inSize = layer->insData.size();
266 if (inSize != 0) continue;
267 if (parseInfo.inputPorts.size() == 0)
268 THROW_IE_EXCEPTION << "Layer " << layer->name << " does not have any input";
269 SetLayerInput(*_network, inputData->getName(), layer, parseInfo.inputPorts[0].portId);
272 // Modification of default input precision which should be used for input blob
273 // Q78 needs an I16 otherwise pixels will overflow
274 // FP16 requires to pass FP32 as input from user
275 Precision inputPrecision;
276 inputPrecision = layer->precision == Precision::Q78 ? Precision::I16 :
277 layer->precision == Precision::FP16 ? Precision::FP32 : static_cast<Precision::ePrecision>(layer->precision);
279 auto inputLayer = std::make_shared<GenericLayer>(LayerParams({inputData->getName(), "input", inputPrecision}));
280 inputLayer->outData.push_back(inputData);
281 _network->addLayer(inputLayer);
282 inputData->creatorLayer = inputLayer;
284 InputsDataMap inputs;
285 _network->getInputsInfo(inputs);
286 if (inputs.size() != 1) {
287 THROW_IE_EXCEPTION << "IR v1 must have one input layer";
289 inputs.begin()->second->setInputPrecision(inputPrecision);
291 // And we need to leave original input precision unmodified for proper handling in plugin
292 inputData->setPrecision(layer->precision);
295 if (!inputWasSet) THROW_IE_EXCEPTION << "network does not have any input layer";
296 } else { // version 2: inputs are marked as input layers
297 auto keep_input_info = [&] (DataPtr &in_data) {
298 InputInfo::Ptr info(new InputInfo());
299 info->setInputData(in_data);
300 Precision prc = info->getInputPrecision();
302 // Convert precision into native format (keep element size)
303 prc = prc == Precision::Q78 ? Precision::I16 :
304 prc == Precision::FP16 ? Precision::FP32 :
305 static_cast<Precision::ePrecision>(prc);
307 info->setInputPrecision(prc);
308 _network->setInputInfo(info);
311 // Keep all data from InputLayers
312 for (auto inLayer : inputLayers) {
313 if (inLayer->outData.size() != 1)
314 THROW_IE_EXCEPTION << "Input layer must have 1 output. "
315 "See documentation for details.";
316 keep_input_info(inLayer->outData[0]);
319 // Keep all data which has no creator layer
320 for (auto &kvp : _network->allLayers()) {
321 const CNNLayer::Ptr& layer = kvp.second;
322 auto pars_info = layersParseInfo[layer->name];
324 if (layer->insData.empty())
325 layer->insData.resize(pars_info.inputPorts.size());
327 for (int i = 0; i < layer->insData.size(); i++) {
328 if (!layer->insData[i].lock()) {
329 std::string data_name = (layer->insData.size() == 1)
331 : layer->name + "." + std::to_string(i);
333 DataPtr data(new Data(data_name,
334 pars_info.inputPorts[i].dims,
335 pars_info.inputPorts[i].precision,
336 TensorDesc::getLayoutByDims(pars_info.inputPorts[i].dims)));
337 data->setDims(pars_info.inputPorts[i].dims);
339 layer->insData[i] = data;
340 data->inputTo[layer->name] = layer;
342 const auto insId = gen_id(pars_info.layerId, pars_info.inputPorts[i].portId);
343 _portsToData[insId] = data;
345 keep_input_info(data);
351 auto statNode = root.child("statistics");
352 ParseStatisticSection(statNode);
354 if (!_network->allLayers().size())
355 THROW_IE_EXCEPTION << "Incorrect model! Network doesn't contain layers.";
357 size_t inputLayersNum(0);
358 CaselessEq<std::string> cmp;
359 for (const auto& kvp : _network->allLayers()) {
360 const CNNLayer::Ptr& layer = kvp.second;
361 if (cmp(layer->type, "Input") || cmp(layer->type, "Const"))
365 if (!inputLayersNum && !cmp(root.name(), "body"))
366 THROW_IE_EXCEPTION << "Incorrect model! Network doesn't contain input layers.";
368 // check all input ports are occupied
369 for (const auto& kvp : _network->allLayers()) {
370 const CNNLayer::Ptr& layer = kvp.second;
371 const LayerParseParameters& parseInfo = layersParseInfo[layer->name];
372 size_t inSize = layer->insData.size();
373 if (inSize != parseInfo.inputPorts.size())
374 THROW_IE_EXCEPTION << "Layer " << layer->name << " does not have any edge connected to it";
376 for (unsigned i = 0; i < inSize; i++) {
377 if (!layer->insData[i].lock()) {
378 THROW_IE_EXCEPTION << "Layer " << layer->name.c_str() << " input port "
379 << parseInfo.inputPorts[i].portId << " is not connected to any data";
382 layer->validateLayer();
385 ParsePreProcess(root);
386 _network->resolveOutput();
388 // Set default output precision to FP32 (for back-compatibility)
389 OutputsDataMap outputsInfo;
390 _network->getOutputsInfo(outputsInfo);
391 for (auto outputInfo : outputsInfo) {
392 if (outputInfo.second->getPrecision() != Precision::FP32 &&
393 outputInfo.second->getPrecision() != Precision::I32) {
394 outputInfo.second->setPrecision(Precision::FP32);
399 int batchSize = GetIntAttr(root, "batch", 1);
400 _network->setBatchSize(batchSize);
406 template<typename BlobType>
407 inline Blob::Ptr GetTypedBlobFromSegment(const TBlob<uint8_t>::Ptr& weights, const WeightSegment& segment) {
408 if (segment.getEnd() > weights->size())
409 THROW_IE_EXCEPTION << "segment exceeds given buffer limits. Please, validate weights file";
411 size_t noOfElement = segment.size / sizeof(BlobType);
412 // RanC: TODO: IR does not provide me with weight slayout.
413 // So far I knew it since I know what layer it is. In generic layers I don't
414 // so until the IR will have the layout and sizes I will pass it as vector and the plugin will have to
415 // validate and undertand what he should get...
416 SizeVector w_dims({noOfElement});
418 typename TBlobProxy<BlobType>::Ptr binBlob(new TBlobProxy<BlobType>(segment.precision, Layout::C, weights, segment.start, w_dims));
420 /* this validation is not reduntant I have no prior knowledge of the weights anymore...
421 if (pbpWeights->byteSize() != lprms.weights.size)
422 THROW_IE_EXCEPTION << "bytes size weights for " << pWL->name << " mismatch, expecting "
423 << pbpWeights->byteSize() << " bytes which are " << pbpWeights->size() << " elements";
428 Blob::Ptr FormatParser::GetBlobFromSegment(const TBlob<uint8_t>::Ptr& weights, const WeightSegment& segment) const {
429 if (segment.precision == Precision::FP32) {
430 return GetTypedBlobFromSegment<float>(weights, segment);
431 } else if (segment.precision == Precision::I32) {
432 return GetTypedBlobFromSegment<int32_t>(weights, segment);
433 } else if (segment.precision == Precision::I16 || segment.precision == Precision::Q78 || segment.precision == Precision::FP16) {
434 return GetTypedBlobFromSegment<short>(weights, segment);
435 } else if (segment.precision == Precision::U8) {
436 return GetTypedBlobFromSegment<uint8_t>(weights, segment);
437 } else if (segment.precision == Precision::I8 || segment.precision == Precision::BIN) {
438 return GetTypedBlobFromSegment<int8_t>(weights, segment);
440 THROW_IE_EXCEPTION << "precision " << segment.precision << " is not supported...";
444 void FormatParser::SetWeights(const TBlob<uint8_t>::Ptr& weights) {
445 for (auto& kvp : _network->allLayers()) {
446 auto fit = layersParseInfo.find(kvp.second->name);
447 // todo: may check that earlier - while parsing...
448 if (fit == layersParseInfo.end())
449 THROW_IE_EXCEPTION << "Internal Error: ParseInfo for " << kvp.second->name << " are missing...";
450 auto& lprms = fit->second;
452 WeightableLayer* pWL = dynamic_cast<WeightableLayer*>(kvp.second.get());
453 if (pWL != nullptr) {
454 if (lprms.blobs.find("weights") != lprms.blobs.end()) {
455 if (lprms.prms.type == "BinaryConvolution") {
456 auto segment = lprms.blobs["weights"];
457 if (segment.getEnd() > weights->size())
458 THROW_IE_EXCEPTION << "segment exceeds given buffer limits. Please, validate weights file";
459 size_t noOfElement = segment.size;
460 SizeVector w_dims({noOfElement});
461 typename TBlobProxy<uint8_t>::Ptr binBlob(new TBlobProxy<uint8_t>(Precision::BIN, Layout::C, weights, segment.start, w_dims));
463 pWL->_weights = binBlob;
465 pWL->_weights = GetBlobFromSegment(weights, lprms.blobs["weights"]);
467 pWL->blobs["weights"] = pWL->_weights;
469 if (lprms.blobs.find("biases") != lprms.blobs.end()) {
470 pWL->_biases = GetBlobFromSegment(weights, lprms.blobs["biases"]);
471 pWL->blobs["biases"] = pWL->_biases;
474 auto pGL = kvp.second.get();
475 if (pGL == nullptr) continue;
476 for (auto s : lprms.blobs) {
477 pGL->blobs[s.first] = GetBlobFromSegment(weights, s.second);
480 // Some layer can specify additional action to prepare weights
481 if (fit->second.internalWeightSet)
482 fit->second.internalWeightSet(weights);
484 for (auto &kvp : _preProcessSegments) {
485 const std::string &inputName = kvp.first;
486 auto &segments = kvp.second;
487 auto inputInfo = _network->getInput(inputName);
488 if (!inputInfo) THROW_IE_EXCEPTION << "Internal error: missing input name " << inputName;
490 auto dims = inputInfo->getDims();
491 auto width = dims[0];
492 auto height = dims[1];
494 PreProcessInfo &pp = inputInfo->getPreProcess();
496 for (size_t c = 0; c < segments.size(); c++) {
497 if (segments[c].size == 0)
499 Blob::Ptr blob = GetBlobFromSegment(weights, segments[c]);
500 blob->Reshape({ width, height }, Layout::HW); // to fit input image sizes (summing it is an image)
501 pp.setMeanImageForChannel(blob, c);
506 void FormatParser::ParseDims(SizeVector& dims, const pugi::xml_node &parentNode) const {
507 for (auto node = parentNode.child("dim"); !node.empty(); node = node.next_sibling("dim")) {
508 unsigned int dim = 0;
509 const pugi::char_t* dimVal = node.child_value();
510 stringstream ss(dimVal);
511 if (!(ss >> dim) || dim == 0) {
512 THROW_IE_EXCEPTION << "dimension (" << dimVal << ") in node " << node.name() << " must be a positive integer: at offset "
513 << node.offset_debug();
519 dims.insert(dims.begin(), 1); // for batch, in version 1, in version 2 it is already there.
522 const DataPtr& FormatParser::GetDataBy(int layer_id, int port_id) const {
523 const auto id = gen_id(layer_id, port_id);
524 const auto &found = _portsToData.find(id);
525 if (found == _portsToData.end())
526 THROW_IE_EXCEPTION << "No data found for layer_id=" << layer_id << " port_id=" << port_id;
527 return found->second;
530 DataPtr FormatParser::ParseInputData(pugi::xml_node& root) const {
531 auto inputNode = root.child("input");
532 if (inputNode.empty()) {
533 THROW_IE_EXCEPTION << "No input node in network, missing <input>";
536 auto inputName = GetStrAttr(inputNode, "name", "input");
537 SizeVector inputDims;
539 ParseDims(inputDims, inputNode);
541 DataPtr& inputData = _network->getData(inputName);
542 inputData.reset(new Data(inputName, inputDims, _network->getPrecision(), TensorDesc::getLayoutByDims(inputDims)));
543 inputData->setDims(inputDims);
547 void FormatParser::ParsePreProcess(pugi::xml_node& root) {
549 <pre-process mean-precision="FP32">
551 <mean value = ”104” / > // in case of constant
553 <mean offset = "121930449" size = "51529" / > // in case of array – ref to the .bin file
554 <scale value = "1.2">
559 auto ppNode = root.child("pre-process");
560 if (ppNode.empty()) {
563 // find out to what input this belongs to
564 std::string inputName;
565 InputInfo::Ptr preProcessInput;
567 inputName = GetStrAttr(ppNode, "reference-layer-name", "");
568 inputName = trim(inputName);
569 if (inputName.empty()) {
570 // fallback (old format), look for the picture in the inputs
571 InputsDataMap inputs;
572 _network->getInputsInfo(inputs);
574 if (inputs.empty()) THROW_IE_EXCEPTION << "network has no input";
576 for (auto i : inputs) {
577 if (i.second->getDims().size() == 4) {
578 preProcessInput = i.second;
582 if (!preProcessInput) {
583 preProcessInput = inputs.begin()->second;
586 inputName = preProcessInput->name();
588 preProcessInput = _network->getInput(inputName);
589 if (!preProcessInput)
590 THROW_IE_EXCEPTION << "pre-process name ref '" << inputName << "' refers to un-existing input";
593 // dims vector without batch size
594 SizeVector inputDims = preProcessInput->getDims();
596 if (inputDims.size() < 2)
597 THROW_IE_EXCEPTION << "network did not define input dimensions properly";
598 size_t noOfChannels = inputDims[inputDims.size() - 2];
599 size_t width = inputDims[0];
600 size_t height = inputDims[1];
602 PreProcessInfo &pp = preProcessInput->getPreProcess();
603 std::vector<WeightSegment> &segments = _preProcessSegments[inputName];
605 pp.init(noOfChannels);
607 segments.resize(noOfChannels);
609 auto meanSegmentPrecision = GetPrecisionAttr(ppNode, "mean-precision", Precision::UNSPECIFIED);
612 InferenceEngine::PreProcessChannel::Ptr preProcessChannel;
615 std::unordered_set<int> idsForMeanValue;
616 std::unordered_set<int> idsForMeanImage;
618 FOREACH_CHILD(chan, ppNode, "channel") {
619 int chanNo = GetIntAttr(chan, "id", lastChanNo + 1);
620 if (chanNo >= static_cast<int>(noOfChannels) || chanNo < 0) {
621 THROW_IE_EXCEPTION << "Pre-process channel id invalid: " << chanNo;
624 preProcessChannel = pp[chanNo];
625 WeightSegment& preProcessSegment = segments[chanNo];
627 auto meanNode = chan.child("mean");
628 if (!meanNode.empty()) {
629 if (!meanNode.attribute("value") && (!meanNode.attribute("size"))) {
630 THROW_IE_EXCEPTION << "mean should have at least one of the following attribute: value, size";
632 if (meanNode.attribute("value")) {
633 preProcessChannel->meanValue = GetFloatAttr(meanNode, "value");
634 idsForMeanValue.insert(chanNo);
636 if (meanNode.attribute("size")) {
637 idsForMeanImage.insert(chanNo);
638 preProcessSegment.size = static_cast<size_t>(GetIntAttr(meanNode, "size"));
639 preProcessSegment.start = static_cast<size_t>(GetIntAttr(meanNode, "offset"));
640 preProcessSegment.precision = meanSegmentPrecision;
641 if (width*height*meanSegmentPrecision.size() != preProcessSegment.size) {
642 THROW_IE_EXCEPTION << "mean blob size mismatch expected input, got: "
643 << preProcessSegment.size << " extpecting " << width
644 << " x " << height << " x " << meanSegmentPrecision.size();
646 if (!meanSegmentPrecision || meanSegmentPrecision == Precision::MIXED)
647 THROW_IE_EXCEPTION << "mean blob defined without specifying precision.";
650 auto scaleNode = chan.child("scale");
651 if (!scaleNode.empty() && scaleNode.attribute("value")) {
652 preProcessChannel->stdScale = GetFloatAttr(scaleNode, "value");
656 if (idsForMeanImage.size() == noOfChannels) {
657 pp.setVariant(MEAN_IMAGE);
658 } else if (idsForMeanValue.size() == noOfChannels) {
659 pp.setVariant(MEAN_VALUE);
660 } else if ((idsForMeanImage.size() == 0) && (idsForMeanValue.size() == 0)) {
663 std::string validMeanValuesIds = "";
664 std::string validMeanImageIds = "";
665 for (auto id : idsForMeanValue) { validMeanValuesIds += std::to_string(id) + " "; }
666 for (auto id : idsForMeanImage) { validMeanImageIds += std::to_string(id) + " "; }
667 THROW_IE_EXCEPTION << "mean is not provided for all channels\n"
668 "Provided mean values for : " << validMeanValuesIds << "\n"
669 "Provided mean image for: " << validMeanImageIds;
673 const std::vector<std::shared_ptr<BaseCreator> >& FormatParser::getCreators() const {
674 // there should be unique_ptr but it cant be used with initializer lists
675 static std::vector<std::shared_ptr<BaseCreator> > creators = {
676 std::make_shared<LayerCreator<PowerLayer>>("Power"),
677 std::make_shared<LayerCreator<ConvolutionLayer>>("Convolution"),
678 std::make_shared<LayerCreator<DeconvolutionLayer>>("Deconvolution"),
679 std::make_shared<LayerCreator<PoolingLayer>>("Pooling"),
680 std::make_shared<LayerCreator<FullyConnectedLayer>>("InnerProduct"),
681 std::make_shared<LayerCreator<FullyConnectedLayer>>("FullyConnected"),
682 std::make_shared<LayerCreator<NormLayer>>("LRN"),
683 std::make_shared<LayerCreator<NormLayer>>("Norm"),
684 std::make_shared<LayerCreator<SoftMaxLayer>>("Softmax"),
685 std::make_shared<LayerCreator<GRNLayer>>("GRN"),
686 std::make_shared<LayerCreator<MVNLayer>>("MVN"),
687 std::make_shared<LayerCreator<ReLULayer>>("ReLU"),
688 std::make_shared<LayerCreator<ClampLayer>>("Clamp"),
689 std::make_shared<LayerCreator<SplitLayer>>("Split"),
690 std::make_shared<LayerCreator<SplitLayer>>("Slice"),
691 std::make_shared<LayerCreator<ConcatLayer>>("Concat"),
692 std::make_shared<LayerCreator<EltwiseLayer>>("Eltwise"),
693 std::make_shared<LayerCreator<GemmLayer>>("Gemm"),
694 std::make_shared<LayerCreator<PadLayer>>("Pad"),
695 std::make_shared<LayerCreator<GatherLayer>>("Gather"),
696 std::make_shared<LayerCreator<StridedSliceLayer>>("StridedSlice"),
697 std::make_shared<LayerCreator<ShuffleChannelsLayer>>("ShuffleChannels"),
698 std::make_shared<LayerCreator<DepthToSpaceLayer>>("DepthToSpace"),
699 std::make_shared<LayerCreator<SpaceToDepthLayer>>("SpaceToDepth"),
700 std::make_shared<LayerCreator<ReverseSequenceLayer>>("ReverseSequence"),
701 std::make_shared<LayerCreator<SqueezeLayer>>("Squeeze"),
702 std::make_shared<LayerCreator<UnsqueezeLayer>>("Unsqueeze"),
703 std::make_shared<LayerCreator<RangeLayer>>("Range"),
704 std::make_shared<LayerCreator<ExpandLayer>>("Expand"),
705 std::make_shared<LayerCreator<ScaleShiftLayer>>("ScaleShift"),
706 std::make_shared<LayerCreator<PReLULayer>>("PReLU"),
707 std::make_shared<LayerCreator<CropLayer>>("Crop"),
708 std::make_shared<LayerCreator<ReshapeLayer>>("Reshape"),
709 std::make_shared<LayerCreator<ReshapeLayer>>("Flatten"),
710 std::make_shared<LayerCreator<TileLayer>>("Tile"),
711 std::make_shared<ActivationLayerCreator>("Activation"),
712 std::make_shared<LayerCreator<BatchNormalizationLayer>>("BatchNormalization"),
713 std::make_shared<TILayerCreator>("TensorIterator"),
714 std::make_shared<LayerCreator<LSTMCell>>("LSTMCell"),
715 std::make_shared<LayerCreator<GRUCell>>("GRUCell"),
716 std::make_shared<LayerCreator<RNNCell>>("RNNCell"),
717 std::make_shared<LayerCreator<RNNSequenceLayer>>("RNNSequence"),
718 std::make_shared<LayerCreator<RNNSequenceLayer>>("GRUSequence"),
719 std::make_shared<LayerCreator<RNNSequenceLayer>>("LSTMSequence"),
720 std::make_shared<LayerCreator<QuantizeLayer>>("Quantize"),
721 std::make_shared<LayerCreator<BinaryConvolutionLayer>>("BinaryConvolution"),
726 void FormatParser::ParseStatisticSection(const pugi::xml_node& statNode) {
727 auto splitParseCommas = [&](const string& s) ->vector<float> {
736 if (ss.peek() == ',')
743 map<string, NetworkNodeStatsPtr> newNetNodesStats;
745 for (auto layer : statNode.children("layer")) {
746 NetworkNodeStatsPtr nodeStats = NetworkNodeStatsPtr(new NetworkNodeStats());
748 string name = layer.child("name").text().get();
750 newNetNodesStats[name] = nodeStats;
752 nodeStats->_minOutputs = splitParseCommas(layer.child("min").text().get());
753 nodeStats->_maxOutputs = splitParseCommas(layer.child("max").text().get());
756 ICNNNetworkStats *pstats = nullptr;
757 StatusCode s = _network->getStats(&pstats, nullptr);
758 if (s == StatusCode::OK && pstats) {
759 pstats->setNodesStats(newNetNodesStats);