updated readme file due to moving CMake scripts to the root folder
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / cpp_interfaces / impl / ie_infer_request_internal.hpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #pragma once
6
7 #include <map>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <blob_factory.hpp>
12 #include <ie_input_info.hpp>
13 #include <ie_icnn_network.hpp>
14 #include "cpp_interfaces/interface/ie_iinfer_request_internal.hpp"
15 #include "debug.h"
16 #include "cpp_interfaces/exception2status.hpp"
17 #include "ie_preprocess_data.hpp"
18 #include "ie_memcpy.h"
19 #include "ie_compound_blob.h"
20
21 namespace InferenceEngine {
22
23 class ExecutableNetworkInternal;
24
25 typedef std::shared_ptr<ExecutableNetworkInternal> ExecutableNetworkInternalPtr;
26
27 /**
28  * @brief optional implementation of IInferRequestInternal to avoid duplication in all plugins
29  */
30 class InferRequestInternal : virtual public IInferRequestInternal {
31 public:
32     typedef std::shared_ptr<InferRequestInternal> Ptr;
33
34     InferRequestInternal(const InputsDataMap &networkInputs, const OutputsDataMap &networkOutputs)
35             : m_curBatch(-1) {
36         // We should copy maps in order to avoid modifications in the future.
37         for (const auto &it : networkInputs) {
38             InputInfo::Ptr newPtr;
39             if (it.second) {
40                 newPtr.reset(new InputInfo());
41                 DataPtr newData(new Data(*it.second->getInputData()));
42                 newPtr->getPreProcess() = it.second->getPreProcess();
43                 if (newPtr->getPreProcess().getMeanVariant() == MEAN_IMAGE) {
44                     for (size_t i = 0; i < newPtr->getPreProcess().getNumberOfChannels(); i++) {
45                         auto blob = newPtr->getPreProcess()[i]->meanData;
46                         newPtr->getPreProcess()[i]->meanData =
47                                 make_blob_with_precision(newPtr->getPreProcess()[i]->meanData->getTensorDesc());
48                         newPtr->getPreProcess()[i]->meanData->allocate();
49                         ie_memcpy(newPtr->getPreProcess()[i]->meanData->buffer(), newPtr->getPreProcess()[i]->meanData->byteSize(),
50                                   blob->cbuffer(), blob->byteSize());
51                     }
52                 }
53                 newData->getInputTo().clear();
54                 newPtr->setInputData(newData);
55             }
56             _networkInputs[it.first] = newPtr;
57         }
58
59         for (const auto &it : networkOutputs) {
60             DataPtr newData;
61             if (it.second) {
62                 newData.reset(new Data(*it.second));
63                 newData->getInputTo().clear();
64             }
65             _networkOutputs[it.first] = newData;
66         }
67     }
68
69     /**
70      * @brief The minimal infer function to be implemented by plugins. It infers specified input(s) in synchronous mode
71      * @note blocks all method of IInferRequest while request is ongoing (running or waiting in queue)
72      */
73     virtual void InferImpl() = 0;
74
75     /**
76      * @brief Default common implementation for all plugins with checking input and output blobs before inference
77      */
78     void Infer() override {
79         checkBlobs();
80         InferImpl();
81     }
82
83     /**
84      * @brief Given optional implementation of setting blob to avoid need for it to be implemented by plugin
85      * @param name - a name of input or output blob.
86      * @param data - a reference to input or output blob. The type of Blob must correspond to the network input precision and size.
87      */
88     void SetBlob(const char *name, const Blob::Ptr &data) override {
89         IE_PROFILING_AUTO_SCOPE(SetBlob)
90         if (name == nullptr) {
91             THROW_IE_EXCEPTION << NOT_FOUND_str + "Failed to set blob with empty name";
92         }
93         if (!data)
94             THROW_IE_EXCEPTION << NOT_ALLOCATED_str << "Failed to set empty blob with name: \'" << name << "\'";
95         const bool compoundBlobPassed = data->is<CompoundBlob>();
96         if (!compoundBlobPassed && data->buffer() == nullptr)
97             THROW_IE_EXCEPTION << "Input data was not allocated. Input name: \'" << name << "\'";
98         if (data->size() == 0) {
99             THROW_IE_EXCEPTION << "Input data is empty. Input name: \'" << name << "\'";
100         }
101
102         InputInfo::Ptr foundInput;
103         DataPtr foundOutput;
104         size_t dataSize = data->size();
105         if (findInputAndOutputBlobByName(name, foundInput, foundOutput)) {
106             if (foundInput->getPrecision() != data->getTensorDesc().getPrecision()) {
107                 THROW_IE_EXCEPTION << PARAMETER_MISMATCH_str
108                                    << "Failed to set Blob with precision not corresponding to user input precision";
109             }
110
111             const bool preProcRequired = preProcessingRequired(foundInput, data);
112             if (compoundBlobPassed && !preProcRequired) {
113                 THROW_IE_EXCEPTION << NOT_IMPLEMENTED_str
114                                    << "cannot set compound blob: supported only for input pre-processing";
115             }
116
117             if (preProcRequired) {
118                 _preProcData[name] = CreatePreprocDataHelper();
119                 _preProcData[name]->isApplicable(data, _inputs[name]);
120                 // Stores the given blob as ROI blob. It will be used to fill in network input
121                 // during pre-processing
122                 _preProcData[name]->setRoiBlob(data);
123             } else {
124                 size_t inputSize = details::product(foundInput->getTensorDesc().getDims());
125                 if (dataSize != inputSize) {
126                     THROW_IE_EXCEPTION << "Input blob size is not equal network input size ("
127                                        << dataSize << "!=" << inputSize << ").";
128                 }
129                 _inputs[name] = data;
130             }
131         } else {
132             if (compoundBlobPassed) {
133                 THROW_IE_EXCEPTION << NOT_IMPLEMENTED_str
134                                    << "cannot set compound blob: supported only for input pre-processing";
135             }
136             size_t outputSize = details::product(foundOutput->getDims());
137             if (dataSize != outputSize) {
138                 THROW_IE_EXCEPTION << "Output blob size is not equal network output size ("
139                                    << dataSize << "!=" << outputSize << ").";
140             }
141             if (foundOutput->getPrecision() != data->getTensorDesc().getPrecision()) {
142                 THROW_IE_EXCEPTION << PARAMETER_MISMATCH_str
143                                    << "Failed to set Blob with precision not corresponding to user output precision";
144             }
145             _outputs[name] = data;
146         }
147     }
148
149     /**
150      * @brief Given optional implementation of getting blob to avoid need for it to be implemented by plugin
151      * @param name - a name of input or output blob.
152      * @param data - a reference to input or output blob. The type of Blob must correspond to the network input precision and size.
153      * @note if ROI blob was previously set it is returned (without dimensions checks) instead of default blob.
154      */
155     void GetBlob(const char *name, Blob::Ptr &data) override {
156         IE_PROFILING_AUTO_SCOPE(GetBlob)
157         InputInfo::Ptr foundInput;
158         DataPtr foundOutput;
159         if (findInputAndOutputBlobByName(name, foundInput, foundOutput)) {
160             // ROI blob is returned only if it was set previously. Otherwise default blob is returned.
161             auto it = _preProcData.find(name);
162             if (it != _preProcData.end()) {
163                 data = it->second->getRoiBlob();
164             } else {
165                 data = _inputs[name];
166                 checkBlob(data, name, true, foundInput->getTensorDesc().getDims());
167             }
168         } else {
169             data = _outputs[name];
170             checkBlob(data, name, false, foundOutput->getTensorDesc().getDims());
171         }
172     }
173
174     void setPointerToExecutableNetworkInternal(ExecutableNetworkInternalPtr exeNetwork) {
175         _exeNetwork = exeNetwork;
176     }
177
178     void checkBlobs() const {
179         for (auto const &input : _inputs) {
180             checkBlob(input.second, input.first, true);
181         }
182         for (auto const &output : _outputs) {
183             checkBlob(output.second, output.first, false);
184         }
185     }
186
187     void SetBatch(int batch) override {
188         THROW_IE_EXCEPTION << "Dynamic batch is not supported";
189     };
190
191     /**
192      * @brief Checks and executes input data pre-processing if needed.
193      */
194     void execDataPreprocessing(InferenceEngine::BlobMap& inputs, bool serial = false) {
195         for (auto &input : inputs) {
196             // If there is a pre-process entry for an input then it must be pre-processed
197             // using preconfigured resize algorithm.
198             auto it = _preProcData.find(input.first);
199             if (it != _preProcData.end()) {
200                 _preProcData[input.first]->execute(input.second,
201                                                    _networkInputs[input.first]->getPreProcess(),
202                                                    serial,
203                                                    m_curBatch);
204             }
205         }
206     }
207
208 protected:
209     InferenceEngine::InputsDataMap _networkInputs;
210     InferenceEngine::OutputsDataMap _networkOutputs;
211     InferenceEngine::BlobMap _inputs;
212     InferenceEngine::BlobMap _outputs;
213     ExecutableNetworkInternalPtr _exeNetwork;
214     std::map<std::string, PreProcessDataPtr> _preProcData;  // pre-process data per input
215     int m_curBatch;  // current batch value used in dynamic batching
216
217 protected:
218     /**
219      * @brief helper to find input or output blob by name
220      * @param name - a name of input or output blob.
221      * @return true - if loaded network has input with provided name,
222      *         false - if loaded network has output with provided name
223      * @throws [parameter_mismatch] exception if input and output has the same name
224      * @throws [not_found] exception if there is no input and output layers with given name
225      */
226     bool findInputAndOutputBlobByName(const char *name, InputInfo::Ptr &foundInput, DataPtr &foundOutput) const {
227         foundInput = nullptr;
228         foundOutput = nullptr;
229         if (_networkInputs.empty() || _networkOutputs.empty()) {
230             THROW_IE_EXCEPTION << "Internal error: network inputs and outputs is not set";
231         }
232         auto foundInputPair = std::find_if(std::begin(_networkInputs),
233                                            std::end(_networkInputs),
234                                            [&](const std::pair<std::string, InputInfo::Ptr> &pair) {
235                                                return pair.first == name;
236                                            });
237         auto foundOutputPair = std::find_if(std::begin(_networkOutputs),
238                                             std::end(_networkOutputs),
239                                             [&](const std::pair<std::string, DataPtr> &pair) {
240                                                 return pair.first == name;
241                                             });
242         if (foundOutputPair == std::end(_networkOutputs) && (foundInputPair == std::end(_networkInputs))) {
243             THROW_IE_EXCEPTION << NOT_FOUND_str << "Failed to find input or output with name: \'" << name << "\'";
244         }
245         if (foundInputPair != std::end(_networkInputs)) {
246             foundInput = foundInputPair->second;
247             return true;
248         } else {
249             foundOutput = foundOutputPair->second;
250             return false;
251         }
252     }
253
254     void checkBlob(const Blob::Ptr &blob, const std::string &name, bool isInput, const SizeVector& refDims = {}) const {
255         std::string bType = isInput ? "Input" : "Output";
256         std::string sType = isInput ? "input" : "output";
257         std::string strNotAllocated(bType + " data was not allocated.");
258         std::string strNotMatched("The " + sType + " blob size is not equal to the network " + sType + " size");
259
260         if (!blob) THROW_IE_EXCEPTION << strNotAllocated;
261         size_t refSize;
262         if (refDims.empty()) {
263             SizeVector dims;
264             if (isInput) {
265                 auto foundInputPair = std::find_if(std::begin(_networkInputs),
266                                                    std::end(_networkInputs),
267                                                    [&](const std::pair<std::string, InputInfo::Ptr>& pair) {
268                                                        return pair.first == name;
269                                                    });
270                 if (foundInputPair == std::end(_networkInputs)) {
271                     THROW_IE_EXCEPTION << NOT_FOUND_str << "Failed to find input with name: \'" << name << "\'";
272                 }
273                 dims = foundInputPair->second->getTensorDesc().getDims();
274             } else {
275                 auto foundOutputPair = std::find_if(std::begin(_networkOutputs),
276                                                     std::end(_networkOutputs),
277                                                     [&](const std::pair<std::string, DataPtr>& pair) {
278                                                         return pair.first == name;
279                                                     });
280                 if (foundOutputPair == std::end(_networkOutputs)) {
281                     THROW_IE_EXCEPTION << NOT_FOUND_str << "Failed to find output with name: \'" << name << "\'";
282                 }
283                 dims = foundOutputPair->second->getTensorDesc().getDims();
284             }
285             refSize = details::product(dims);
286         } else {
287             refSize = details::product(refDims);
288         }
289
290         if (refSize != blob->size()) {
291             THROW_IE_EXCEPTION << strNotMatched + ": got " << blob->size() << " expecting " << refSize;
292         }
293         if (blob->buffer() == nullptr) THROW_IE_EXCEPTION << strNotAllocated;
294     }
295
296     /**
297      * @brief helper to decide whether pre-processing is required
298      * @param info InputInfo corresponding to input blob
299      * @param blob input Blob object corresponding to input info
300      * @return true if pre-processing is required, false otherwise
301      */
302     bool preProcessingRequired(const InputInfo::Ptr& info, const Blob::Ptr& blob) {
303         // pre-processing is required if:
304         // 1. resize algorithm is specified (resize required)
305         // 2. color format specified:
306         // 2.a. color format is not equal to network's expected (color conversion required)
307         // 2.b. network's layout != blob's layout (reorder required)
308         const auto& preProcessInfo = info->getPreProcess();
309         const auto inputColorFormat = preProcessInfo.getColorFormat();
310         // FIXME: support other network's input formats once the API is ready. Assuming input is in
311         // the BGR format by default
312         const auto networkColorFormat = ColorFormat::BGR;
313
314         const bool colorFormatSpecified = inputColorFormat != ColorFormat::RAW;
315         return preProcessInfo.getResizeAlgorithm() != ResizeAlgorithm::NO_RESIZE
316             || (colorFormatSpecified && inputColorFormat != networkColorFormat)
317             || (colorFormatSpecified && info->getLayout() != blob->getTensorDesc().getLayout());
318     }
319 };
320
321 }  // namespace InferenceEngine