ie_infer_request_internal.hpp
1 // Copyright (C) 2018-2020 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 
5 #pragma once
6 
7 #include <ie_icnn_network.hpp>
8 #include <ie_input_info.hpp>
9 #include <map>
10 #include <memory>
11 #include <string>
12 #include <utility>
13 
16 #include "cpp_interfaces/interface/ie_iinfer_request_internal.hpp"
18 #include "debug.h"
19 #include "ie_compound_blob.h"
20 #include "ie_memcpy.h"
21 #include "ie_preprocess_data.hpp"
22 
23 namespace InferenceEngine {
24 
25 class ExecutableNetworkInternal;
26 
27 /**
28  * @brief An optimal implementation of IInferRequestInternal interface to avoid duplication in all plugins
29  * This base class is recommended to be used as a base class for plugin synchronous inference request implementation.
30  * @ingroup ie_dev_api_infer_request_api
31  */
33 public:
34  /**
35  * @brief A shared pointer to a InferRequestInternal implementation.
36  */
37  typedef std::shared_ptr<InferRequestInternal> Ptr;
38 
39  /**
40  * @brief Constructs a new instance.
41  * @param[in] networkInputs The network inputs info
42  * @param[in] networkOutputs The network outputs data
43  */
44  InferRequestInternal(const InputsDataMap& networkInputs, const OutputsDataMap& networkOutputs): m_curBatch(-1) {
45  // // We should copy maps since they can be overriden in SetBlob with preprocess
46  copyInputOutputInfo(networkInputs, networkOutputs, _networkInputs, _networkOutputs);
47  }
48 
49  /**
50  * @brief The minimal infer function to be implemented by plugins. It infers specified input(s) in synchronous mode
51  * @note
52  * * This method is used in InferRequestInternal::Infer, which calls the common code first and after uses this
53  * plugin dependent implementation.
54  * * Blocks all method of IInferRequest while request is ongoing (running or waiting in queue)
55  */
56  virtual void InferImpl() = 0;
57 
58  /**
59  * @brief Default common implementation for all plugins with checking input and output blobs before inference
60  */
61  void Infer() override {
62  checkBlobs();
63  InferImpl();
64  }
65 
66  /**
67  * @brief Given optional implementation of setting blob to avoid need for it to be implemented by plugin
68  * @param name - a name of input or output blob.
69  * @param data - a reference to input or output blob. The type of Blob must correspond to the network input
70  * precision and size.
71  */
72  void SetBlob(const char* name, const Blob::Ptr& data) override {
73  OV_ITT_SCOPED_TASK(itt::domains::Plugin, "SetBlob");
74  if (name == nullptr) {
75  THROW_IE_EXCEPTION << NOT_FOUND_str + "Failed to set blob with empty name";
76  }
77  if (!data) THROW_IE_EXCEPTION << NOT_ALLOCATED_str << "Failed to set empty blob with name: \'" << name << "\'";
78  const bool compoundBlobPassed = data->is<CompoundBlob>();
79  if (!compoundBlobPassed && data->buffer() == nullptr)
80  THROW_IE_EXCEPTION << "Input data was not allocated. Input name: \'" << name << "\'";
81  if (data->size() == 0) {
82  THROW_IE_EXCEPTION << "Input data is empty. Input name: \'" << name << "\'";
83  }
84 
85  InputInfo::Ptr foundInput;
86  DataPtr foundOutput;
87  size_t dataSize = data->size();
88  if (findInputAndOutputBlobByName(name, foundInput, foundOutput)) {
89  if (foundInput->getPrecision() != data->getTensorDesc().getPrecision()) {
91  << "Failed to set Blob with precision not corresponding to user input precision";
92  }
93 
94  const bool preProcRequired = preProcessingRequired(foundInput, data);
95  if (compoundBlobPassed && !preProcRequired) {
97  << "cannot set compound blob: supported only for input pre-processing";
98  }
99 
100  if (preProcRequired) {
101  if (_preProcData.find(name) == _preProcData.end()) {
102  _preProcData.emplace(name, CreatePreprocDataHelper());
103  }
104  _preProcData[name]->isApplicable(data, _inputs[name]);
105  // Stores the given blob as ROI blob. It will be used to fill in network input
106  // during pre-processing
107  _preProcData[name]->setRoiBlob(data);
108  } else {
109  size_t inputSize = details::product(foundInput->getTensorDesc().getDims());
110  if (dataSize != inputSize) {
111  THROW_IE_EXCEPTION << "Input blob size is not equal network input size (" << dataSize
112  << "!=" << inputSize << ").";
113  }
114  _inputs[name] = data;
115  }
116  } else {
117  if (compoundBlobPassed) {
119  << "cannot set compound blob: supported only for input pre-processing";
120  }
121  size_t outputSize = details::product(foundOutput->getDims());
122  if (dataSize != outputSize) {
123  THROW_IE_EXCEPTION << "Output blob size is not equal network output size (" << dataSize
124  << "!=" << outputSize << ").";
125  }
126  if (foundOutput->getPrecision() != data->getTensorDesc().getPrecision()) {
128  << "Failed to set Blob with precision not corresponding to user output precision";
129  }
130  _outputs[name] = data;
131  }
132  }
133 
134  /**
135  * @brief Given optional implementation of getting blob to avoid need for it to be implemented by plugin
136  * @param name - a name of input or output blob.
137  * @param data - a reference to input or output blob. The type of Blob must correspond to the network input
138  * precision and size.
139  * @note if ROI blob was previously set it is returned (without dimensions checks) instead of default blob.
140  */
141  void GetBlob(const char* name, Blob::Ptr& data) override {
142  OV_ITT_SCOPED_TASK(itt::domains::Plugin, "GetBlob");
143  InputInfo::Ptr foundInput;
144  DataPtr foundOutput;
145  const SizeVector oneVector = { 1 };
146  if (findInputAndOutputBlobByName(name, foundInput, foundOutput)) {
147  // ROI blob is returned only if it was set previously. Otherwise default blob is returned.
148  auto it = _preProcData.find(name);
149  if (it != _preProcData.end()) {
150  data = it->second->getRoiBlob();
151  } else {
152  data = _inputs[name];
153  checkBlob(data, name, true,
154  foundInput->getTensorDesc().getLayout() != SCALAR
155  ? foundInput->getTensorDesc().getDims()
156  : oneVector);
157  }
158  } else {
159  data = _outputs[name];
160  checkBlob(data, name, false,
161  foundOutput->getTensorDesc().getLayout() != SCALAR
162  ? foundOutput->getTensorDesc().getDims()
163  : oneVector);
164  }
165  }
166 
167  /**
168  * @brief Sets pre-process for input data
169  * @param name Name of input blob.
170  * @param data - a reference to input or output blob. The type of Blob must correspond to the network input precision and size.
171  * @param info Preprocess info for blob.
172  */
173  void SetBlob(const char* name, const Blob::Ptr& data, const PreProcessInfo& info) override {
174  InputInfo::Ptr foundInput;
175  DataPtr foundOutput;
176  if (findInputAndOutputBlobByName(name, foundInput, foundOutput)) {
177  copyPreProcess(info, foundInput->getPreProcess());
178  } else {
179  THROW_IE_EXCEPTION << "Pre-process can't be set to output blob";
180  }
181 
182  SetBlob(name, data);
183  }
184 
185  /**
186  * @brief Gets pre-process for input data
187  * @param name Name of input blob.
188  * @param info pointer to a pointer to PreProcessInfo structure
189  */
190  void GetPreProcess(const char* name, const PreProcessInfo** info) const override {
191  InputInfo::Ptr foundInput;
192  DataPtr foundOutput;
193  if (findInputAndOutputBlobByName(name, foundInput, foundOutput)) {
194  *info = &foundInput->getPreProcess();
195  } else {
196  THROW_IE_EXCEPTION << "Output blob can't have pre-processing";
197  }
198  }
199 
200  void SetBatch(int batch) override {
201  (void)batch;
202  THROW_IE_EXCEPTION << "Dynamic batch is not supported";
203  };
204 
205  /**
206  * @brief Sets the pointer to executable network internal.
207  * @note Needed to correctly handle ownership between objects.
208  * @param[in] exeNetwork The executable network
209  */
210  void setPointerToExecutableNetworkInternal(std::shared_ptr<ExecutableNetworkInternal> exeNetwork) {
211  _exeNetwork = exeNetwork;
212  }
213 
214  /**
215  * @brief Checks that both inputs and outputs blob are valid. Throws an exception if they are not.
216  */
217  virtual void checkBlobs() {
218  for (auto const& input : _inputs) {
219  checkBlob(input.second, input.first, true);
220  }
221  for (auto const& output : _outputs) {
222  checkBlob(output.second, output.first, false);
223  }
224  }
225 
226  std::vector<IVariableStateInternal::Ptr> QueryState() override {
227  // meaning base plugin reports as no state available - plugin owners need to create proper override of this
228  THROW_IE_EXCEPTION << "Plugin doesn't override QueryState";
229  return {};
230  }
231 
232 protected:
233  InferenceEngine::InputsDataMap _networkInputs; //!< Holds information about network inputs info
234  InferenceEngine::OutputsDataMap _networkOutputs; //!< Holds information about network outputs data
235  InferenceEngine::BlobMap _inputs; //!< A map of network input blobs
236  InferenceEngine::BlobMap _outputs; //!< A map of network output blobs
237  std::map<std::string, PreProcessDataPtr> _preProcData; //!< A map of pre-process data per input
238  int m_curBatch; //!< Current batch value used in dynamic batching
239 
240  /**
241  * @brief A shared pointer to ExecutableNetworkInternal interface
242  * @note Needed to correctly handle ownership between objects.
243  */
244  std::shared_ptr<ExecutableNetworkInternal> _exeNetwork;
245 
246  /**
247  * @brief Checks and executes input data pre-processing if needed.
248  * @param inputs Inputs blobs to perform preprocessing on
249  * @param serial Whether to use multiple threads to execute the step
250  */
251  void execDataPreprocessing(InferenceEngine::BlobMap& inputs, bool serial = false) {
252  for (auto& input : inputs) {
253  // If there is a pre-process entry for an input then it must be pre-processed
254  // using preconfigured resize algorithm.
255  auto it = _preProcData.find(input.first);
256  if (it != _preProcData.end()) {
257  _preProcData[input.first]->execute(input.second, _networkInputs[input.first]->getPreProcess(), serial,
258  m_curBatch);
259  }
260  }
261  }
262 
263  /**
264  * @brief Helper function to find input or output blob by name
265  * @param name A name of input or output blob.
266  * @param foundInput A pointer to input information if found.
267  * @param foundOutput A pointer to output DataPtr if found.
268  * @return `True` - if loaded network has input with provided name,
269  * `false` - if loaded network has output with provided name
270  * @throws [parameter_mismatch] exception if input and output has the same name
271  * @throws [not_found] exception if there is no input and output layers with given name
272  */
273  bool findInputAndOutputBlobByName(const char* name, InputInfo::Ptr& foundInput, DataPtr& foundOutput) const {
274  foundInput = nullptr;
275  foundOutput = nullptr;
276  if (_networkInputs.empty() || _networkOutputs.empty()) {
277  THROW_IE_EXCEPTION << "Internal error: network inputs and outputs is not set";
278  }
279  auto foundInputPair = std::find_if(std::begin(_networkInputs), std::end(_networkInputs),
280  [&](const std::pair<std::string, InputInfo::Ptr>& pair) {
281  return pair.first == name;
282  });
283  auto foundOutputPair = std::find_if(std::begin(_networkOutputs), std::end(_networkOutputs),
284  [&](const std::pair<std::string, DataPtr>& pair) {
285  return pair.first == name;
286  });
287  if (foundOutputPair == std::end(_networkOutputs) && (foundInputPair == std::end(_networkInputs))) {
288  THROW_IE_EXCEPTION << NOT_FOUND_str << "Failed to find input or output with name: \'" << name << "\'";
289  }
290  if (foundInputPair != std::end(_networkInputs)) {
291  foundInput = foundInputPair->second;
292  return true;
293  } else {
294  foundOutput = foundOutputPair->second;
295  return false;
296  }
297  }
298 
299  /**
300  * @brief Check that @p blob is valid. Throws an exception if it's not.
301  *
302  * @param[in] blob The blob to check
303  * @param[in] name The name of input or output depending of if the @p blob is input or output
304  * @param[in] isInput Indicates if @p is input
305  * @param[in] refDims The reference dims, empty if not specified
306  */
307  void checkBlob(const Blob::Ptr& blob, const std::string& name, bool isInput, const SizeVector& refDims = {}) const {
308  std::string bType = isInput ? "Input" : "Output";
309  std::string sType = isInput ? "input" : "output";
310  std::string strNotAllocated(bType + " data was not allocated.");
311  std::string strNotMatched("The " + sType + " blob size is not equal to the network " + sType + " size");
312 
313  if (!blob) {
314  THROW_IE_EXCEPTION << strNotAllocated;
315  }
316  size_t refSize;
317  if (refDims.empty()) {
318  SizeVector dims;
319  if (isInput) {
320  auto foundInputPair = std::find_if(std::begin(_networkInputs), std::end(_networkInputs),
321  [&](const std::pair<std::string, InputInfo::Ptr>& pair) {
322  return pair.first == name;
323  });
324  if (foundInputPair == std::end(_networkInputs)) {
325  THROW_IE_EXCEPTION << NOT_FOUND_str << "Failed to find input with name: \'" << name << "\'";
326  }
327  dims = foundInputPair->second->getTensorDesc().getDims();
328  refSize = foundInputPair->second->getTensorDesc().getLayout() != SCALAR
329  ? details::product(dims)
330  : 1;
331  } else {
332  auto foundOutputPair = std::find_if(std::begin(_networkOutputs), std::end(_networkOutputs),
333  [&](const std::pair<std::string, DataPtr>& pair) {
334  return pair.first == name;
335  });
336  if (foundOutputPair == std::end(_networkOutputs)) {
337  THROW_IE_EXCEPTION << NOT_FOUND_str << "Failed to find output with name: \'" << name << "\'";
338  }
339  dims = foundOutputPair->second->getTensorDesc().getDims();
340  refSize = foundOutputPair->second->getTensorDesc().getLayout() != SCALAR
341  ? details::product(dims)
342  : 1;
343  }
344  } else {
345  refSize = details::product(refDims);
346  }
347 
348  if (refSize != blob->size()) {
349  THROW_IE_EXCEPTION << strNotMatched + ": got " << blob->size() << " expecting " << refSize;
350  }
351  if (blob->buffer() == nullptr) THROW_IE_EXCEPTION << strNotAllocated;
352  }
353 
354  /**
355  * @brief Checks whether pre-processing step is required for a given input
356  * @param info InputInfo corresponding to input blob
357  * @param blob Input Blob object corresponding to input info
358  * @return `True` if pre-processing is required, `false` otherwise
359  */
360  bool preProcessingRequired(const InputInfo::Ptr& info, const Blob::Ptr& blob) {
361  // pre-processing is required if:
362  // 1. resize algorithm is specified (resize required)
363  // 2. color format specified:
364  // 2.a. color format is not equal to network's expected (color conversion required)
365  // 2.b. network's layout != blob's layout (reorder required)
366  const auto& preProcessInfo = info->getPreProcess();
367  const auto inputColorFormat = preProcessInfo.getColorFormat();
368  // FIXME: support other network's input formats once the API is ready. Assuming input is in
369  // the BGR format by default
370  const auto networkColorFormat = ColorFormat::BGR;
371 
372  const bool colorFormatSpecified = inputColorFormat != ColorFormat::RAW;
373  return preProcessInfo.getResizeAlgorithm() != ResizeAlgorithm::NO_RESIZE ||
374  (colorFormatSpecified && inputColorFormat != networkColorFormat) ||
375  (colorFormatSpecified && info->getLayout() != blob->getTensorDesc().getLayout());
376  }
377 };
378 
379 } // namespace InferenceEngine
std::shared_ptr< Blob > Ptr
An internal API of synchronous inference request to be implemented by plugin, which is used in InferR...
Definition: ie_iinfer_request_internal.hpp:24
An optimal implementation of IInferRequestInternal interface to avoid duplication in all plugins This...
Definition: ie_infer_request_internal.hpp:32
InferenceEngine::BlobMap _outputs
A map of network output blobs.
Definition: ie_infer_request_internal.hpp:236
void SetBlob(const char *name, const Blob::Ptr &data) override
Given optional implementation of setting blob to avoid need for it to be implemented by plugin.
Definition: ie_infer_request_internal.hpp:72
bool findInputAndOutputBlobByName(const char *name, InputInfo::Ptr &foundInput, DataPtr &foundOutput) const
Helper function to find input or output blob by name.
Definition: ie_infer_request_internal.hpp:273
std::shared_ptr< InferRequestInternal > Ptr
A shared pointer to a InferRequestInternal implementation.
Definition: ie_infer_request_internal.hpp:37
virtual void checkBlobs()
Checks that both inputs and outputs blob are valid. Throws an exception if they are not.
Definition: ie_infer_request_internal.hpp:217
void SetBatch(int batch) override
Sets new batch size when dynamic batching is enabled in executable network that created this request.
Definition: ie_infer_request_internal.hpp:200
std::map< std::string, PreProcessDataPtr > _preProcData
A map of pre-process data per input.
Definition: ie_infer_request_internal.hpp:237
InferenceEngine::InputsDataMap _networkInputs
Holds information about network inputs info.
Definition: ie_infer_request_internal.hpp:233
std::shared_ptr< ExecutableNetworkInternal > _exeNetwork
A shared pointer to ExecutableNetworkInternal interface.
Definition: ie_infer_request_internal.hpp:244
void GetBlob(const char *name, Blob::Ptr &data) override
Given optional implementation of getting blob to avoid need for it to be implemented by plugin.
Definition: ie_infer_request_internal.hpp:141
virtual void InferImpl()=0
The minimal infer function to be implemented by plugins. It infers specified input(s) in synchronous ...
void GetPreProcess(const char *name, const PreProcessInfo **info) const override
Gets pre-process for input data.
Definition: ie_infer_request_internal.hpp:190
void Infer() override
Default common implementation for all plugins with checking input and output blobs before inference.
Definition: ie_infer_request_internal.hpp:61
bool preProcessingRequired(const InputInfo::Ptr &info, const Blob::Ptr &blob)
Checks whether pre-processing step is required for a given input.
Definition: ie_infer_request_internal.hpp:360
void setPointerToExecutableNetworkInternal(std::shared_ptr< ExecutableNetworkInternal > exeNetwork)
Sets the pointer to executable network internal.
Definition: ie_infer_request_internal.hpp:210
int m_curBatch
Current batch value used in dynamic batching.
Definition: ie_infer_request_internal.hpp:238
void SetBlob(const char *name, const Blob::Ptr &data, const PreProcessInfo &info) override
Sets pre-process for input data.
Definition: ie_infer_request_internal.hpp:173
void execDataPreprocessing(InferenceEngine::BlobMap &inputs, bool serial=false)
Checks and executes input data pre-processing if needed.
Definition: ie_infer_request_internal.hpp:251
InferenceEngine::OutputsDataMap _networkOutputs
Holds information about network outputs data.
Definition: ie_infer_request_internal.hpp:234
InferenceEngine::BlobMap _inputs
A map of network input blobs.
Definition: ie_infer_request_internal.hpp:235
void checkBlob(const Blob::Ptr &blob, const std::string &name, bool isInput, const SizeVector &refDims={}) const
Check that blob is valid. Throws an exception if it's not.
Definition: ie_infer_request_internal.hpp:307
InferRequestInternal(const InputsDataMap &networkInputs, const OutputsDataMap &networkOutputs)
Constructs a new instance.
Definition: ie_infer_request_internal.hpp:44
std::vector< IVariableStateInternal::Ptr > QueryState() override
Queries memory states.
Definition: ie_infer_request_internal.hpp:226
std::shared_ptr< InputInfo > Ptr
Basic debugging tools.
Wrappers from c++ function to c-style one.
#define NOT_IMPLEMENTED_str
Defines the not implemented message.
Definition: exception2status.hpp:111
#define NOT_ALLOCATED_str
Defines the not allocated message.
Definition: exception2status.hpp:117
T product(std::vector< T, A > const &vec)
multiply vector's values
Definition: debug.h:144
#define NOT_FOUND_str
Defines the not found message.
Definition: exception2status.hpp:87
#define PARAMETER_MISMATCH_str
Defines the parameter mismatch message.
Definition: exception2status.hpp:75
SCALAR
std::shared_ptr< Data > DataPtr
std::vector< size_t > SizeVector
#define THROW_IE_EXCEPTION
std::map< std::string, DataPtr > OutputsDataMap
std::map< std::string, InputInfo::Ptr > InputsDataMap
Inference Engine plugin API wrapper, to be used by particular implementors.
Defines a ie_memcpy to safely (SDL-friendly) copy arrays.
Defines openvino domains for tracing.