1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
6 #include "cnn_network_impl.hpp"
12 #include <shape_infer/ie_reshaper.hpp>
14 #include "graph_tools.hpp"
16 #include "network_serializer.h"
19 using namespace InferenceEngine;
20 using namespace InferenceEngine::details;
22 CNNNetworkImpl::CNNNetworkImpl(): _targetDevice(TargetDevice::eDefault), _stats(new CNNNetworkStatsImpl()) {
25 CNNNetworkImpl::~CNNNetworkImpl() {
26 for (auto& data : _data) {
27 for (auto& input : data.second->getInputTo()) {
33 void CNNNetworkImpl::getOutputsInfo(std::map<std::string, DataPtr>& out) const noexcept {
37 void CNNNetworkImpl::getInputsInfo(InputsDataMap& inputs) const noexcept {
41 void CNNNetworkImpl::addLayer(const CNNLayerPtr& layer) noexcept {
42 _layers[layer->name] = layer;
45 void CNNNetworkImpl::removeLayer(const string& layerName) {
46 auto it = _layers.find(layerName);
47 if (it != _layers.end()) { _layers.erase(it); }
50 void CNNNetworkImpl::removeData(const string& dataName) {
51 auto it = _data.find(dataName);
52 if (it != _data.end()) { _data.erase(it); }
55 void CNNNetworkImpl::validate(int version) {
57 std::set<std::string> layerNames;
58 std::set<std::string> dataNames;
61 this->getInputsInfo(inputs);
63 THROW_IE_EXCEPTION << "No input layers";
66 bool res = CNNNetForestDFS(CNNNetGetAllInputLayers(*this), [&](CNNLayerPtr layer) {
67 std::string layerName = layer->name;
69 for (auto i : layer->insData) {
72 auto inputTo = data->getInputTo();
73 auto iter = inputTo.find(layerName);
74 auto dataName = data->name;
75 if (iter == inputTo.end()) {
76 THROW_IE_EXCEPTION << "Data " << data->getName() << " which inserted into the layer "
78 << " does not point at this layer";
80 if (!data->getCreatorLayer().lock()) {
81 THROW_IE_EXCEPTION << "Data " << dataName << " has no creator layer";
84 THROW_IE_EXCEPTION << "Data which inserted into the layer " << layerName << " is nullptr";
87 for (auto data : layer->outData) {
88 auto inputTo = data->getInputTo();
89 std::string dataName = data->getName();
90 for (auto layerIter : inputTo) {
91 CNNLayerPtr layerInData = layerIter.second;
93 THROW_IE_EXCEPTION << "Layer which takes data " << dataName << " is nullptr";
95 auto insertedDatas = layerInData->insData;
97 auto it = std::find_if(insertedDatas.begin(), insertedDatas.end(),
98 [&](InferenceEngine::DataWeakPtr& d) {
99 return d.lock() == data;
101 if (it == insertedDatas.end()) {
102 THROW_IE_EXCEPTION << "Layer " << layerInData->name << " which takes data " << dataName
103 << " does not point at this data";
106 auto dataNameSetPair = dataNames.insert(dataName);
107 if (!dataNameSetPair.second) {
108 THROW_IE_EXCEPTION << "Data name " << dataName << " is not unique";
111 auto layerSetPair = layerNames.insert(layerName);
112 if (!layerSetPair.second) {
113 THROW_IE_EXCEPTION << "Layer name " << layerName << " is not unique";
118 std::string inputType = "Input";
119 for (auto i : inputs) {
120 CNNLayerPtr layer = i.second->getInputData()->creatorLayer.lock();
121 if (layer && !equal(layer->type, inputType)) {
122 THROW_IE_EXCEPTION << "Input layer " << layer->name
123 << " should have Input type but actually its type is " << layer->type;
128 THROW_IE_EXCEPTION << "Sorting not possible, due to existed loop.";
133 StatusCode CNNNetworkImpl::getLayerByName(const char* layerName, CNNLayerPtr& out, ResponseDesc* resp) const noexcept {
134 auto it = _layers.find(layerName);
135 if (it == _layers.end())
136 return DescriptionBuffer(NOT_FOUND, resp) << "Layer " << layerName << " not found in network";
141 StatusCode CNNNetworkImpl::addOutput(const std::string& layerName, size_t outputIndex, ResponseDesc* resp) noexcept {
142 CNNLayerPtr outLayer;
143 auto rc = getLayerByName(layerName.c_str(), outLayer, resp);
144 if (rc != OK) return rc;
146 if (outputIndex >= outLayer->outData.size())
147 return DescriptionBuffer(OUT_OF_BOUNDS, resp) << "port index " << outputIndex
148 << " exceeds layer's outputs which is "
149 << outLayer->outData.size();
150 shared_ptr<Data> outData = outLayer->outData[outputIndex];
151 _outputData[outData->getName()] = outData;
155 void CNNNetworkImpl::resolveOutput() {
156 // check orphan nodes...
157 for (auto kvp : _data) {
158 if (!kvp.second->isInitialized())
159 THROW_IE_EXCEPTION << "data name [" << kvp.first << "] dimensions is not known";
161 // data nodes not going to any layer are basically graph output...
162 if (kvp.second->getInputTo().empty()) {
163 _outputData[kvp.first] = kvp.second;
168 void CNNNetworkImpl::addOutput(const string& dataName) {
169 auto it = _data.find(dataName);
170 if (it == _data.end()) {
171 THROW_IE_EXCEPTION << "data [" << dataName << "] doesn't exist";
173 auto data = it->second;
174 assert(data->getName() == dataName);
175 _outputData[dataName] = data;
178 StatusCode CNNNetworkImpl::setBatchSize(const size_t size) noexcept {
179 return setBatchSize(size, nullptr);
182 size_t CNNNetworkImpl::getBatchSize() const noexcept {
183 if (!_inputData.size())
185 // currently CNNNetworkImpl::setBatchSize set the same values
186 // for the latest dim as a batch, we can take the first input
187 // and return batch size for it
188 SizeVector dims = _inputData.cbegin()->second->getDims();
189 // 3D input layout doesn't have batch notation for input so batch is 1
190 if (dims.size() == 3 || dims.size() == 1) {
193 return dims.at(dims.size() - 1);
197 CNNNetworkImpl::reshape(const std::map<std::string, std::vector<size_t>>& inputShapes,
198 ResponseDesc* responseDesc) noexcept {
200 if (!_reshaper) _reshaper = std::make_shared<ShapeInfer::Reshaper>(*this);
201 _reshaper->run(inputShapes);
202 } catch (const InferenceEngineException& e) {
203 return DescriptionBuffer(GENERAL_ERROR, responseDesc) << e.what();
204 } catch (const std::exception& e) {
205 return DescriptionBuffer(UNEXPECTED, responseDesc) << e.what();
207 return DescriptionBuffer(UNEXPECTED, responseDesc);
213 CNNNetworkImpl::AddExtension(const InferenceEngine::IShapeInferExtensionPtr& extension,
214 InferenceEngine::ResponseDesc* resp) noexcept {
216 if (!_reshaper) _reshaper = std::make_shared<ShapeInfer::Reshaper>(*this);
217 _reshaper->AddExtension(extension);
218 } catch (const InferenceEngineException& e) {
219 return DescriptionBuffer(GENERAL_ERROR, resp) << e.what();
220 } catch (const std::exception& e) {
221 return DescriptionBuffer(UNEXPECTED, resp) << e.what();
223 return DescriptionBuffer(UNEXPECTED, resp);
228 StatusCode CNNNetworkImpl::serialize(const std::string &xmlPath, const std::string &binPath, ResponseDesc* resp) const noexcept {
230 NetworkSerializer::serialize(xmlPath, binPath, (InferenceEngine::ICNNNetwork&)*this);
231 } catch (const InferenceEngineException& e) {
232 return DescriptionBuffer(GENERAL_ERROR, resp) << e.what();
233 } catch (const std::exception& e) {
234 return DescriptionBuffer(UNEXPECTED, resp) << e.what();
236 return DescriptionBuffer(UNEXPECTED, resp);
241 StatusCode CNNNetworkImpl::setBatchSize(size_t size, ResponseDesc* responseDesc) noexcept {
242 auto originalBatchSize = getBatchSize();
243 if (originalBatchSize == size)
245 SizeVector dims = _inputData.cbegin()->second->getDims();
247 // 3D input layout doesn't have batch notation
248 if (dims.size() == 3 || dims.size() == 1) {
249 return DescriptionBuffer(PARAMETER_MISMATCH, responseDesc) << "Cannot set batch for 1D/3D input";
252 for (auto layer : _data) {
253 SizeVector dims = layer.second->getDims();
254 // Calculates original size for batch = 1
255 size_t diff = dims.at(0) / originalBatchSize;
256 dims.at(0) = size * diff;
257 layer.second->setDims(dims);
262 StatusCode CNNNetworkImpl::setBatchSizeReshape(size_t size, ResponseDesc* responseDesc) noexcept {
263 InputShapes inputShapes;
264 for (const auto& pair : _inputData) {
265 auto info = pair.second;
267 auto data = info->getInputData();
269 auto dims = data->getTensorDesc().getDims();
271 inputShapes[data->name] = dims;
275 return reshape(inputShapes, responseDesc);