Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / cnn_network_impl.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include <ie_common.h>
6 #include "cnn_network_impl.hpp"
7 #include <memory>
8 #include <map>
9 #include <set>
10 #include <string>
11 #include <cassert>
12 #include <shape_infer/ie_reshaper.hpp>
13 #include "debug.h"
14 #include "graph_tools.hpp"
15 #include <vector>
16 #include "network_serializer.h"
17
18 using namespace std;
19 using namespace InferenceEngine;
20 using namespace InferenceEngine::details;
21
22 CNNNetworkImpl::CNNNetworkImpl(): _targetDevice(TargetDevice::eDefault), _stats(new CNNNetworkStatsImpl()) {
23 }
24
25 CNNNetworkImpl::~CNNNetworkImpl() {
26     for (auto& data : _data) {
27         for (auto& input : data.second->getInputTo()) {
28             input.second.reset();
29         }
30     }
31 }
32
33 void CNNNetworkImpl::getOutputsInfo(std::map<std::string, DataPtr>& out) const noexcept {
34     out = _outputData;
35 }
36
37 void CNNNetworkImpl::getInputsInfo(InputsDataMap& inputs) const noexcept {
38     inputs = _inputData;
39 }
40
41 void CNNNetworkImpl::addLayer(const CNNLayerPtr& layer) noexcept {
42     _layers[layer->name] = layer;
43 }
44
45 void CNNNetworkImpl::removeLayer(const string& layerName) {
46     auto it = _layers.find(layerName);
47     if (it != _layers.end()) { _layers.erase(it); }
48 }
49
50 void CNNNetworkImpl::removeData(const string& dataName) {
51     auto it = _data.find(dataName);
52     if (it != _data.end()) { _data.erase(it); }
53 }
54
55 void CNNNetworkImpl::validate(int version) {
56     if (version != 1) {
57         std::set<std::string> layerNames;
58         std::set<std::string> dataNames;
59
60         InputsDataMap inputs;
61         this->getInputsInfo(inputs);
62         if (inputs.empty()) {
63             THROW_IE_EXCEPTION << "No input layers";
64         }
65
66         bool res = CNNNetForestDFS(CNNNetGetAllInputLayers(*this), [&](CNNLayerPtr layer) {
67             std::string layerName = layer->name;
68
69             for (auto i : layer->insData) {
70                 auto data = i.lock();
71                 if (data) {
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 "
77                                            << layerName
78                                            << " does not point at this layer";
79                     }
80                     if (!data->getCreatorLayer().lock()) {
81                         THROW_IE_EXCEPTION << "Data " << dataName << " has no creator layer";
82                     }
83                 } else {
84                     THROW_IE_EXCEPTION << "Data which inserted into the layer " << layerName << " is nullptr";
85                 }
86             }
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;
92                     if (!layerInData) {
93                         THROW_IE_EXCEPTION << "Layer which takes data " << dataName << " is nullptr";
94                     }
95                     auto insertedDatas = layerInData->insData;
96
97                     auto it = std::find_if(insertedDatas.begin(), insertedDatas.end(),
98                                            [&](InferenceEngine::DataWeakPtr& d) {
99                                                return d.lock() == data;
100                                            });
101                     if (it == insertedDatas.end()) {
102                         THROW_IE_EXCEPTION << "Layer " << layerInData->name << " which takes data " << dataName
103                                            << " does not point at this data";
104                     }
105                 }
106                 auto dataNameSetPair = dataNames.insert(dataName);
107                 if (!dataNameSetPair.second) {
108                     THROW_IE_EXCEPTION << "Data name " << dataName << " is not unique";
109                 }
110             }
111             auto layerSetPair = layerNames.insert(layerName);
112             if (!layerSetPair.second) {
113                 THROW_IE_EXCEPTION << "Layer name " << layerName << " is not unique";
114             }
115         }, false);
116
117
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;
124             }
125         }
126
127         if (!res) {
128             THROW_IE_EXCEPTION << "Sorting not possible, due to existed loop.";
129         }
130     }
131 }
132
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";
137     out = it->second;
138     return OK;
139 }
140
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;
145
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;
152     return OK;
153 }
154
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";
160
161         // data nodes not going to any layer are basically graph output...
162         if (kvp.second->getInputTo().empty()) {
163             _outputData[kvp.first] = kvp.second;
164         }
165     }
166 }
167
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";
172     }
173     auto data = it->second;
174     assert(data->getName() == dataName);
175     _outputData[dataName] = data;
176 }
177
178 StatusCode CNNNetworkImpl::setBatchSize(const size_t size) noexcept {
179     return setBatchSize(size, nullptr);
180 }
181
182 size_t CNNNetworkImpl::getBatchSize() const noexcept {
183     if (!_inputData.size())
184         return 0;
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) {
191         return 1;
192     }
193     return dims.at(dims.size() - 1);
194 }
195
196 StatusCode
197 CNNNetworkImpl::reshape(const std::map<std::string, std::vector<size_t>>& inputShapes,
198                         ResponseDesc* responseDesc) noexcept {
199     try {
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();
206     } catch (...) {
207         return DescriptionBuffer(UNEXPECTED, responseDesc);
208     }
209     return OK;
210 }
211
212 StatusCode
213 CNNNetworkImpl::AddExtension(const InferenceEngine::IShapeInferExtensionPtr& extension,
214                              InferenceEngine::ResponseDesc* resp) noexcept {
215     try {
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();
222     } catch (...) {
223         return DescriptionBuffer(UNEXPECTED, resp);
224     }
225     return OK;
226 }
227
228 StatusCode CNNNetworkImpl::serialize(const std::string &xmlPath, const std::string &binPath, ResponseDesc* resp) const noexcept {
229     try {
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();
235     } catch (...) {
236         return DescriptionBuffer(UNEXPECTED, resp);
237     }
238     return OK;
239 }
240
241 StatusCode CNNNetworkImpl::setBatchSize(size_t size, ResponseDesc* responseDesc) noexcept {
242     auto originalBatchSize = getBatchSize();
243     if (originalBatchSize == size)
244         return OK;
245     SizeVector dims = _inputData.cbegin()->second->getDims();
246
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";
250     }
251
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);
258     }
259     return OK;
260 }
261
262 StatusCode CNNNetworkImpl::setBatchSizeReshape(size_t size, ResponseDesc* responseDesc) noexcept {
263     InputShapes inputShapes;
264     for (const auto& pair : _inputData) {
265         auto info = pair.second;
266         if (info) {
267             auto data = info->getInputData();
268             if (data) {
269                 auto dims = data->getTensorDesc().getDims();
270                 dims[0] = size;
271                 inputShapes[data->name] = dims;
272             }
273         }
274     }
275     return reshape(inputShapes, responseDesc);
276 }