From 03c7ff3f6188240baaeaeb405a357a0c58195fec Mon Sep 17 00:00:00 2001 From: Nikhil Raj Date: Tue, 22 Aug 2023 12:00:04 +0100 Subject: IVGCVSW-7702 Update Doxygen Docu for 23.08 Signed-off-by: Nikhil Raj Change-Id: I357a9f7e47614589327c1ac5d95b6224ff77103d --- latest/_conversion_utils_8hpp_source.html | 1267 +++++++++++++++++++++++++++++ 1 file changed, 1267 insertions(+) create mode 100644 latest/_conversion_utils_8hpp_source.html (limited to 'latest/_conversion_utils_8hpp_source.html') diff --git a/latest/_conversion_utils_8hpp_source.html b/latest/_conversion_utils_8hpp_source.html new file mode 100644 index 0000000000..26a8eb72c2 --- /dev/null +++ b/latest/_conversion_utils_8hpp_source.html @@ -0,0 +1,1267 @@ + + + + + + + + +Arm NN: shim/sl/canonical/ConversionUtils.hpp Source File + + + + + + + + + + + + + + + + +
+
+ + + + ArmNN + + + +
+
+  23.08 +
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
ConversionUtils.hpp
+
+
+Go to the documentation of this file.
1 //
+
2 // Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
+
3 // SPDX-License-Identifier: MIT
+
4 //
+
5 
+
6 #pragma once
+
7 
+
8 #include "CanonicalUtils.hpp"
+
9 
+
10 #include <armnn/ArmNN.hpp>
+
11 #include <armnn/BackendHelper.hpp>
+
12 #include <armnn/utility/Assert.hpp>
+ + +
15 
+ +
17 #include <armnnUtils/Transpose.hpp>
+
18 
+
19 #include <ActivationFunctor.h>
+
20 #include <CpuExecutor.h>
+
21 #include <OperationsUtils.h>
+
22 
+ +
24 
+
25 #include <log/log.h>
+
26 #include <vector>
+
27 
+
28 inline const android::nn::Model::Subgraph& getMainModel(const android::nn::Model& model) { return model.main; }
+
29 
+
30 namespace armnn_driver
+
31 {
+
32 
+
33 ///
+
34 /// Helper classes
+
35 ///
+
36 
+
37 #include <nnapi/OperandTypes.h>
+
38 #include <nnapi/Result.h>
+
39 #include <nnapi/TypeUtils.h>
+
40 #include <nnapi/Types.h>
+
41 #include <nnapi/Validation.h>
+
42 
+ + +
45 using OperandLifeTime = ::android::nn::Operand::LifeTime;
+ + + + +
50 
+ +
52 {
+
53  ConversionData(const std::vector<armnn::BackendId>& backends)
+
54  : m_Backends(backends)
+
55  , m_Network(nullptr, nullptr)
+ +
57  {}
+
58 
+
59  const std::vector<armnn::BackendId> m_Backends;
+ +
61  std::vector<armnn::IOutputSlot*> m_OutputSlotForOperand;
+
62  std::vector<::android::nn::RunTimePoolInfo> m_MemPools;
+ +
64 };
+
65 
+ +
67 {
+
68 public:
+ +
70  LayerInputHandle(bool valid, armnn::IOutputSlot* outputSlot, armnn::TensorInfo tensorInfo);
+
71 
+
72  bool IsValid() const;
+
73 
+
74  void Connect(armnn::IInputSlot& inputSlot);
+
75 
+
76  void Disconnect(armnn::IInputSlot& inputSlot);
+
77 
+
78  const armnn::TensorInfo& GetTensorInfo() const;
+
79 
+ +
81 
+ +
83 
+
84 private:
+
85  armnn::IOutputSlot* m_OutputSlot;
+
86  bool m_Valid;
+
87  armnn::TensorInfo m_TensorInfo;
+
88 };
+
89 
+ +
91 {
+
92 public:
+
93  // Creates an invalid tensor pin (can be used to signal errors)
+
94  // The optional flag can be set to indicate the tensor values were missing, but it was otherwise valid
+
95  ConstTensorPin(bool optional = false);
+
96 
+
97  // @param tensorInfo TensorInfo associated with the tensor.
+
98  // @param valueStart Start address of tensor data. Belongs to one of the memory pools associated with
+
99  // the model being converted.
+
100  // @param numBytes Number of bytes for the tensor data.
+
101  ConstTensorPin(armnn::TensorInfo& tensorInfo, const void* valueStart, uint32_t numBytes,
+
102  const armnn::PermutationVector& mappings);
+
103 
+
104  ConstTensorPin(const ConstTensorPin& other) = delete;
+
105  ConstTensorPin(ConstTensorPin&& other) = default;
+
106 
+
107  bool IsValid() const;
+
108  bool IsOptional() const;
+
109 
+
110  const armnn::ConstTensor& GetConstTensor() const;
+
111  const armnn::ConstTensor* GetConstTensorPtr() const;
+
112 
+
113 private:
+
114  armnn::ConstTensor m_ConstTensor;
+
115 
+
116  // Owned memory for swizzled tensor data, only required if the tensor needed
+
117  // swizzling. Otherwise, @ref m_ConstTensor will reference memory from one of
+
118  // the pools associated with the model being converted.
+
119  std::vector<uint8_t> m_SwizzledTensorData;
+
120 
+
121  // optional flag to indicate that an invalid tensor pin is not an error, but the optional values were not given
+
122  bool m_Optional;
+
123 };
+
124 
+ +
126 {
+
127  Success,
+ + +
130 };
+
131 
+
132 } // namespace armnn_driver
+
133 
+
134 ///
+
135 /// Utility functions
+
136 ///
+
137 
+
138 namespace
+
139 {
+
140 using namespace armnn_driver;
+
141 
+
142 // Convenience function to log the reason for failing to convert a model.
+
143 // @return Always returns false (so that it can be used by callers as a quick way to signal an error and return)
+
144 template<class... Args>
+
145 static bool Fail(const char* formatStr, Args&&... args)
+
146 {
+
147  ALOGD(formatStr, std::forward<Args>(args)...);
+
148  return false;
+
149 }
+
150 
+
151 // Convenience macro to call an Is*Supported function and log caller name together with reason for lack of support.
+
152 // Called as: FORWARD_LAYER_SUPPORT_FUNC(__func__, Is*Supported, backends, a, b, c, d, e)
+
153 #define FORWARD_LAYER_SUPPORT_FUNC(funcName, func, backends, supported, setBackend, ...) \
+
154 try \
+
155 { \
+
156  for (auto&& backendId : backends) \
+
157  { \
+
158  auto layerSupportObject = armnn::GetILayerSupportByBackendId(backendId); \
+
159  if (layerSupportObject.IsBackendRegistered()) \
+
160  { \
+
161  std::string reasonIfUnsupported; \
+
162  supported = \
+
163  layerSupportObject.func(__VA_ARGS__, armnn::Optional<std::string&>(reasonIfUnsupported)); \
+
164  if (supported) \
+
165  { \
+
166  setBackend = backendId; \
+
167  break; \
+
168  } \
+
169  else \
+
170  { \
+
171  if (reasonIfUnsupported.size() > 0) \
+
172  { \
+
173  VLOG(DRIVER) << funcName << ": not supported by armnn: " << reasonIfUnsupported.c_str(); \
+
174  } \
+
175  else \
+
176  { \
+
177  VLOG(DRIVER) << funcName << ": not supported by armnn"; \
+
178  } \
+
179  } \
+
180  } \
+
181  else \
+
182  { \
+
183  VLOG(DRIVER) << funcName << ": backend not registered: " << backendId.Get().c_str(); \
+
184  } \
+
185  } \
+
186  if (!supported) \
+
187  { \
+
188  VLOG(DRIVER) << funcName << ": not supported by any specified backend"; \
+
189  } \
+
190 } \
+
191 catch (const armnn::InvalidArgumentException &e) \
+
192 { \
+
193  throw armnn::InvalidArgumentException(e, "Failed to check layer support", CHECK_LOCATION()); \
+
194 }
+
195 
+
196 inline armnn::TensorShape GetTensorShapeForOperand(const Operand& operand)
+
197 {
+
198  return armnn::TensorShape(operand.dimensions.size(), operand.dimensions.data());
+
199 }
+
200 
+
201 // Support within the 1.3 driver for specific tensor data types
+
202 inline bool IsOperandTypeSupportedForTensors(OperandType type)
+
203 {
+
204  return type == OperandType::BOOL ||
+
205  type == OperandType::TENSOR_BOOL8 ||
+
206  type == OperandType::TENSOR_FLOAT16 ||
+
207  type == OperandType::TENSOR_FLOAT32 ||
+
208  type == OperandType::TENSOR_QUANT8_ASYMM ||
+
209  type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED ||
+
210  type == OperandType::TENSOR_QUANT8_SYMM ||
+
211  type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL ||
+
212  type == OperandType::TENSOR_QUANT16_SYMM ||
+
213  type == OperandType::TENSOR_INT32;
+
214 }
+
215 
+
216 inline bool IsBool(Operand operand)
+
217 {
+
218  return operand.type == OperandType::BOOL;
+
219 }
+
220 
+
221 inline bool Is12OrLaterOperand(Operand)
+
222 {
+
223  return true;
+
224 }
+
225 
+
226 
+
227 template<typename LayerHandleType>
+
228 armnn::IConnectableLayer& AddReshapeLayer(armnn::INetwork& network,
+
229  LayerHandleType& inputLayer,
+
230  armnn::TensorInfo reshapeInfo)
+
231 {
+
232  armnn::ReshapeDescriptor reshapeDescriptor;
+
233  reshapeDescriptor.m_TargetShape = reshapeInfo.GetShape();
+
234 
+
235  armnn::IConnectableLayer* reshapeLayer = network.AddReshapeLayer(reshapeDescriptor);
+
236  ARMNN_ASSERT(reshapeLayer != nullptr);
+
237 
+
238  // Attach the input layer to the reshape layer
+
239  inputLayer.Connect(reshapeLayer->GetInputSlot(0));
+
240  reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapeInfo);
+
241 
+
242  return *reshapeLayer;
+
243 }
+
244 
+
245 
+
246  armnn::TensorShape FlattenFullyConnectedInput(const armnn::TensorShape& inputShape,
+
247  const armnn::TensorShape& weightsShape)
+
248 {
+
249  if (inputShape.GetNumDimensions() > 2U)
+
250  {
+
251  unsigned int totalInputElements = inputShape.GetNumElements();
+
252  unsigned int inputSize = weightsShape[1];
+
253 
+
254  unsigned int batchSize = totalInputElements / inputSize;
+
255 
+
256  if(totalInputElements % batchSize != 0)
+
257  {
+
258  throw std::runtime_error("Failed to deduce tensor shape");
+
259  }
+
260 
+
261  return armnn::TensorShape({batchSize, inputSize});
+
262  }
+
263  else
+
264  {
+
265  return inputShape;
+
266  }
+
267 }
+
268 
+
269 inline bool VerifyFullyConnectedShapes(const armnn::TensorShape& inputShape,
+
270  const armnn::TensorShape& weightsShape,
+
271  const armnn::TensorShape& outputShape,
+
272  bool transposeWeightMatrix)
+
273 {
+
274  unsigned int dimIdx = transposeWeightMatrix ? 0 : 1;
+
275  return (inputShape[0] == outputShape[0] && weightsShape[dimIdx] == outputShape[1]);
+
276 }
+
277 
+
278 bool BroadcastTensor(LayerInputHandle& input0,
+
279  LayerInputHandle& input1,
+
280  armnn::IConnectableLayer* startLayer,
+
281  ConversionData& data)
+
282 {
+
283  ARMNN_ASSERT(startLayer != nullptr);
+
284 
+
285  const armnn::TensorInfo& inputInfo0 = input0.GetTensorInfo();
+
286  const armnn::TensorInfo& inputInfo1 = input1.GetTensorInfo();
+
287 
+
288  unsigned int inputDimensions0 = inputInfo0.GetNumDimensions();
+
289  unsigned int inputDimensions1 = inputInfo1.GetNumDimensions();
+
290 
+
291  if (inputDimensions0 == inputDimensions1)
+
292  {
+
293  // The inputs have the same number of dimensions, simply connect them to the given layer as they are
+
294  input0.Connect(startLayer->GetInputSlot(0));
+
295  input1.Connect(startLayer->GetInputSlot(1));
+
296 
+
297  return true;
+
298  }
+
299 
+
300  // Since the number of dimensions do not match then we need to add degenerate dimensions
+
301  // to the "smaller" tensor using a reshape, while keeping the order of the inputs.
+
302 
+
303  unsigned int maxInputDimensions = std::max(inputDimensions0, inputDimensions1);
+
304  unsigned int sizeDifference = std::abs(armnn::numeric_cast<int>(inputDimensions0) -
+
305  armnn::numeric_cast<int>(inputDimensions1));
+
306 
+
307  bool input0IsSmaller = inputDimensions0 < inputDimensions1;
+
308  LayerInputHandle& smallInputHandle = input0IsSmaller ? input0 : input1;
+
309  const armnn::TensorInfo& smallInfo = smallInputHandle.GetTensorInfo();
+
310 
+
311  const armnn::TensorShape& smallShape = smallInfo.GetShape();
+
312  std::vector<unsigned int> reshapedDimensions(maxInputDimensions, 1);
+
313  for (unsigned int i = sizeDifference; i < maxInputDimensions; i++)
+
314  {
+
315  reshapedDimensions[i] = smallShape[i - sizeDifference];
+
316  }
+
317 
+
318  armnn::TensorInfo reshapedInfo = smallInfo;
+
319  reshapedInfo.SetShape(armnn::TensorShape{ armnn::numeric_cast<unsigned int>(reshapedDimensions.size()),
+
320  reshapedDimensions.data() });
+
321 
+
322  // RehsapeDescriptor that is ignored in the IsReshapeSupported function
+
323  armnn::ReshapeDescriptor reshapeDescriptor;
+
324 
+
325  bool isSupported = false;
+
326  armnn::BackendId setBackend;
+ +
328  IsReshapeSupported,
+
329  data.m_Backends,
+
330  isSupported,
+
331  setBackend,
+
332  smallInfo,
+
333  reshapedInfo,
+
334  reshapeDescriptor);
+
335  if (!isSupported)
+
336  {
+
337  return false;
+
338  }
+
339 
+
340  ARMNN_ASSERT(data.m_Network != nullptr);
+
341  armnn::IConnectableLayer& reshapeLayer = AddReshapeLayer(*data.m_Network, smallInputHandle, reshapedInfo);
+
342  reshapeLayer.SetBackendId(setBackend);
+
343 
+
344  if (input0IsSmaller)
+
345  {
+
346  // Input0 is the "smaller" tensor, connect the reshape layer as follows:
+
347  //
+
348  // Input0 Input1
+
349  // | |
+
350  // Reshape |
+
351  // \ /
+
352  // StartLayer
+
353 
+
354  reshapeLayer.GetOutputSlot(0).Connect(startLayer->GetInputSlot(0));
+
355  input1.Connect(startLayer->GetInputSlot(1));
+
356  }
+
357  else
+
358  {
+
359  // Input1 is the "smaller" tensor, connect the reshape layer as follows:
+
360  //
+
361  // Input0 Input1
+
362  // | |
+
363  // | Reshape
+
364  // \ /
+
365  // StartLayer
+
366 
+
367  input0.Connect(startLayer->GetInputSlot(0));
+
368  reshapeLayer.GetOutputSlot(0).Connect(startLayer->GetInputSlot(1));
+
369  }
+
370 
+
371  return true;
+
372 }
+
373 
+
374 void CalcPadding(uint32_t input,
+
375  uint32_t kernel,
+
376  uint32_t stride,
+
377  uint32_t& outPadHead,
+
378  uint32_t& outPadTail,
+
379  PaddingScheme scheme)
+
380 {
+
381  int32_t padHead;
+
382  int32_t padTail;
+
383  calculateExplicitPadding(input, stride, kernel, scheme, &padHead, &padTail);
+
384  outPadHead = armnn::numeric_cast<uint32_t>(padHead);
+
385  outPadTail = armnn::numeric_cast<uint32_t>(padTail);
+
386 }
+
387 
+
388 void CalcPadding(uint32_t input, uint32_t kernel, uint32_t stride, uint32_t dilation, uint32_t& outPadHead,
+
389  uint32_t& outPadTail, ::android::nn::PaddingScheme scheme)
+
390 {
+
391  int32_t padHead;
+
392  int32_t padTail;
+
393  calculateExplicitPadding(input, stride, dilation, kernel, scheme, &padHead, &padTail);
+
394  outPadHead = armnn::numeric_cast<uint32_t>(padHead);
+
395  outPadTail = armnn::numeric_cast<uint32_t>(padTail);
+
396 }
+
397 
+
398 inline void CalcPaddingTransposeConv(uint32_t output, uint32_t kernel, int32_t stride, int32_t& outPadHead,
+
399  int32_t& outPadTail, ::android::nn::PaddingScheme scheme)
+
400 {
+
401  calculateExplicitPaddingTransposeConv(output, stride, kernel, scheme, &outPadHead, &outPadTail);
+
402 }
+
403 
+
404 Shape GetOperandShape(const Operand& operand)
+
405 {
+
406  Shape shape;
+
407  shape.type = OperandType(operand.type);
+
408  shape.dimensions = operand.dimensions;
+
409  shape.scale = operand.scale;
+
410  shape.offset = operand.zeroPoint;
+
411  return shape;
+
412 }
+
413 
+
414 
+
415 // ArmNN requires the bias scale to be equal to the product of the weight and input scales, which is also
+
416 // what AndroidNN requires. However for some of the AndroidNN tests the values don't exactly match so
+
417 // we accept some tolerance. We don't want ArmNN itself to accept these inconsistencies as it is up to the
+
418 // user (us, in this case) to ensure they match.
+
419 void SanitizeBiasQuantizationScale(armnn::TensorInfo& biasInfo,
+
420  const armnn::TensorInfo& weightInfo,
+
421  const armnn::TensorInfo& inputInfo)
+
422 {
+
423  if (weightInfo.HasPerAxisQuantization())
+
424  {
+
425  // NOTE: Bias scale is always set to 0 for per-axis quantization and
+
426  // it needs to be calculated: scale[i] = input_scale * weight_scale[i]
+
427  auto UpdateBiasScaleValue = [&inputInfo](float biasScale) -> float
+
428  {
+
429  return biasScale * inputInfo.GetQuantizationScale();
+
430  };
+
431 
+
432  std::vector<float> biasScales(weightInfo.GetQuantizationScales());
+
433  std::transform(biasScales.begin(), biasScales.end(), biasScales.begin(), UpdateBiasScaleValue);
+
434 
+
435  biasInfo.SetQuantizationScales(biasScales);
+
436  // bias is expected to be a 1d tensor, set qdim=0
+
437  biasInfo.SetQuantizationDim(0);
+
438 
+
439  VLOG(DRIVER) << "Bias quantization params have been updated for per-axis quantization";
+
440  }
+
441  else
+
442  {
+
443  const float expectedBiasScale = weightInfo.GetQuantizationScale() * inputInfo.GetQuantizationScale();
+
444  if (biasInfo.GetQuantizationScale() != expectedBiasScale)
+
445  {
+
446  if (armnnUtils::within_percentage_tolerance(biasInfo.GetQuantizationScale(), expectedBiasScale, 1.0f))
+
447  {
+
448  VLOG(DRIVER) << "Bias quantization scale has been modified to match input * weights";
+
449  biasInfo.SetQuantizationScale(expectedBiasScale);
+
450  }
+
451  }
+
452  }
+
453 }
+
454 
+
455 // 4D Tensor Permutations
+
456 const armnn::PermutationVector IdentityPermutation4D({ 0U, 1U, 2U, 3U });
+
457 const armnn::PermutationVector IdentityPermutation3D({ 0U, 1U, 2U });
+
458 const armnn::PermutationVector SwapDim2And3({ 0U, 1U, 3U, 2U });
+
459 
+
460 // 3D Permutation Vectors
+
461 const armnn::PermutationVector RotateTensorLeft({ 1U, 2U, 0U });
+
462 const armnn::PermutationVector RotateTensorRight({ 2U, 0U, 1U });
+
463 
+
464 template<typename OSlot>
+
465 armnn::IConnectableLayer& AddTransposeLayer(armnn::INetwork& network, OSlot& input,
+
466  const armnn::PermutationVector& mappings)
+
467 {
+
468  // Add swizzle layer
+
469  armnn::IConnectableLayer* const layer = network.AddTransposeLayer(mappings);
+
470 
+
471  ARMNN_ASSERT(layer != nullptr);
+
472 
+
473  // Connect input to swizzle layer
+
474  input.Connect(layer->GetInputSlot(0));
+
475 
+
476  // Setup swizzled output
+
477  const armnn::TensorInfo outInfo = armnnUtils::TransposeTensorShape(input.GetTensorInfo(), mappings);
+
478  layer->GetOutputSlot(0).SetTensorInfo(outInfo);
+
479 
+
480  return *layer;
+
481 }
+
482 
+
483 bool ValidateConcatOutputShape(const std::vector<armnn::TensorShape> & inputShapes,
+
484  const armnn::TensorShape & outputShape,
+
485  uint32_t concatDim)
+
486 {
+
487  // Validate the output shape is correct given the input shapes (which have just been validated)
+
488  unsigned int numDimensions = inputShapes[0].GetNumDimensions();
+
489  if (outputShape.GetNumDimensions() != numDimensions)
+
490  {
+
491  return Fail("%s: Output shape has wrong number of dimensions", __func__);
+
492  }
+
493 
+
494  unsigned int outputSizeAlongConcatenatedDimension = 0;
+
495  for (unsigned int i = 0; i < inputShapes.size(); i++)
+
496  {
+
497  outputSizeAlongConcatenatedDimension += inputShapes[i][concatDim];
+
498  }
+
499 
+
500  for (unsigned int i = 0; i < numDimensions; ++i)
+
501  {
+
502  if (i == concatDim)
+
503  {
+
504  if (outputShape[i] != outputSizeAlongConcatenatedDimension)
+
505  {
+
506  return Fail(
+
507  "%s: Invalid output shape for dimension %d (%d != %d)",
+
508  __func__,
+
509  i,
+
510  outputShape[i],
+
511  outputSizeAlongConcatenatedDimension);
+
512  }
+
513  }
+
514  else
+
515  {
+
516  if (outputShape[i] != inputShapes[0][i])
+
517  {
+
518  return Fail("%s: Invalid output shape", __func__);
+
519  }
+
520  }
+
521  }
+
522 
+
523  return true;
+
524 }
+
525 
+
526 inline bool RequiresReshape(armnn::TensorShape & inputShape)
+
527 {
+
528  return inputShape.GetNumDimensions() < 3;
+
529 }
+
530 
+
531 inline void SwizzleInputs(armnn::INetwork& network,
+
532  std::vector<LayerInputHandle>& inputs,
+
533  std::vector<armnn::TensorShape>& inputShapes,
+
534  const armnn::PermutationVector& mapping,
+
535  std::vector<armnn::BackendId>& setBackends)
+
536 {
+
537  if (!mapping.IsEqual(IdentityPermutation4D))
+
538  {
+
539  size_t nInputs = inputs.size();
+
540  for (size_t i=0; i<nInputs; ++i)
+
541  {
+
542  // add swizzle layer
+
543  armnn::IConnectableLayer& swizzleLayer = AddTransposeLayer(network, inputs[i], mapping);
+
544  swizzleLayer.SetBackendId(setBackends[i]);
+
545  auto& outputSlot = swizzleLayer.GetOutputSlot(0);
+
546  auto& outputInfo = outputSlot.GetTensorInfo();
+
547  // replace inputs with the swizzled ones
+
548  inputs[i] = LayerInputHandle(true, &outputSlot, outputInfo);
+
549  inputShapes[i] = inputs[i].GetTensorInfo().GetShape();
+
550  }
+
551  }
+
552 }
+
553 
+
554 bool TransposeInputTensors(ConversionData& data,
+
555  std::vector<LayerInputHandle>& inputs,
+
556  std::vector<armnn::TensorShape>& inputShapes,
+
557  const armnn::PermutationVector& mapping)
+
558 {
+
559  // If we have a IdentityPermutation4D or IdentityPermutation3D then we are not permuting
+
560  if (!mapping.IsEqual(IdentityPermutation4D) && !mapping.IsEqual(IdentityPermutation3D))
+
561  {
+
562  std::vector<armnn::BackendId> setBackendsVec;
+
563  armnn::TensorInfo outputTransposeInfo;
+
564  size_t nInputs = inputs.size();
+
565  for (size_t i=0; i<nInputs; ++i)
+
566  {
+
567  // check permute layer
+
568  armnn::TransposeDescriptor transposeDesc;
+
569  transposeDesc.m_DimMappings = mapping;
+
570  outputTransposeInfo = armnnUtils::TransposeTensorShape(inputs[i].GetTensorInfo(), mapping);
+
571 
+
572  bool isSupported = false;
+
573  armnn::BackendId setBackend;
+ +
575  IsTransposeSupported,
+
576  data.m_Backends,
+
577  isSupported,
+
578  setBackend,
+
579  inputs[i].GetTensorInfo(),
+
580  outputTransposeInfo,
+
581  transposeDesc);
+
582  setBackendsVec.push_back(setBackend);
+
583  if (!isSupported)
+
584  {
+
585  return false;
+
586  }
+
587 
+
588  }
+
589  SwizzleInputs(*data.m_Network, inputs, inputShapes, mapping, setBackendsVec);
+
590  }
+
591  return true;
+
592 }
+
593 
+
594 bool CreateConcatPermutationParameters(const unsigned int numberOfDimensions,
+
595  int32_t & concatDimension,
+
596  std::pair<armnn::PermutationVector, armnn::PermutationVector> & permutationPair)
+
597 {
+
598  bool needPermute = false;
+
599  ARMNN_ASSERT(numberOfDimensions >= 3);
+
600 
+
601  // ArmNN uses Compute Library subtensors to perform concatenation
+
602  // This only works when concatenating along dimension 0, 1 or 3 for a 4-D tensor,
+
603  // or along dimension 0 or 2 for a 3-D tensor.
+
604  if (numberOfDimensions == 4 && concatDimension == 2)
+
605  {
+
606  concatDimension = 3;
+
607  permutationPair = std::make_pair(SwapDim2And3, SwapDim2And3);
+
608  needPermute = true;
+
609  }
+
610  else if (numberOfDimensions == 3 && concatDimension == 1)
+
611  {
+
612  concatDimension = 0;
+
613  permutationPair = std::make_pair(RotateTensorLeft, RotateTensorRight);
+
614  needPermute = true;
+
615  }
+
616  // If the tensor is 3-D and the concat dimension is 2 then we don't need to permute but we do need to change the
+
617  // permutation identity to only have 3 dimensions
+
618  else if (numberOfDimensions == 3 && concatDimension == 2)
+
619  {
+
620  permutationPair = std::make_pair(IdentityPermutation3D, IdentityPermutation3D);
+
621  }
+
622  return needPermute;
+
623 }
+
624 
+
625 } // anonymous namespace
+
626 
+
627 namespace armnn_driver
+
628 {
+
629 using namespace android::nn;
+
630 
+
631 //// Creates an ArmNN activation layer and connects it to the given layer, if the
+
632 //// passed in AndroidNN activation function requires so.
+
633 //// @return The end layer of the sequence of layers built for the given AndroidNN
+
634 //// activation function or nullptr if an error occurred (e.g. unsupported activation).
+
635 //// Note that the end layer matches the input layer if no activation is required
+
636 //// (the sequence of layers has length 1).
+ +
638  ActivationFn activation,
+
639  armnn::IConnectableLayer* prevLayer,
+
640  ConversionData& data);
+
641 
+
642 
+
643 inline const Operand* GetInputOperand(const Operation& operation,
+
644  uint32_t inputIndex,
+
645  const Model& model,
+
646  bool failOnIndexOutOfBounds = true)
+
647 {
+
648  if (inputIndex >= operation.inputs.size())
+
649  {
+
650  if (failOnIndexOutOfBounds)
+
651  {
+
652  Fail("%s: invalid input index: %i out of %i", __func__, inputIndex, operation.inputs.size());
+
653  }
+
654  return nullptr;
+
655  }
+
656 
+
657  // Model should have been validated beforehand
+
658  ARMNN_ASSERT(operation.inputs[inputIndex] < getMainModel(model).operands.size());
+
659  return &getMainModel(model).operands[operation.inputs[inputIndex]];
+
660 }
+
661 
+
662 inline const Operand* GetOutputOperand(const Operation& operation,
+
663  uint32_t outputIndex,
+
664  const Model& model)
+
665 {
+
666  if (outputIndex >= operation.outputs.size())
+
667  {
+
668  Fail("%s: invalid output index: %i out of %i", __func__, outputIndex, operation.outputs.size());
+
669  return nullptr;
+
670  }
+
671 
+
672  // Model should have been validated beforehand
+
673  ARMNN_ASSERT(operation.outputs[outputIndex] < getMainModel(model).operands.size());
+
674 
+
675  return &getMainModel(model).operands[operation.outputs[outputIndex]];
+
676 }
+
677 
+
678 const void* GetOperandValueReadOnlyAddress(const Operand& operand,
+
679  const Model& model,
+
680  const ConversionData& data,
+
681  bool optional = false);
+
682 
+
683 inline bool GetOperandType(const Operation& operation,
+
684  uint32_t inputIndex,
+
685  const Model& model,
+
686  OperandType& type)
+
687 {
+
688  const Operand* operand = GetInputOperand(operation, inputIndex, model);
+
689  if (!operand)
+
690  {
+
691  return Fail("%s: invalid input operand at index %i", __func__, inputIndex);
+
692  }
+
693 
+
694  type = operand->type;
+
695  return true;
+
696 }
+
697 
+
698 inline bool IsOperandConstant(const Operand& operand)
+
699 {
+
700  OperandLifeTime lifetime = operand.lifetime;
+
701 
+
702  return lifetime == OperandLifeTime::CONSTANT_COPY ||
+
703  lifetime == OperandLifeTime::CONSTANT_REFERENCE ||
+
704  lifetime == OperandLifeTime::POINTER ||
+
705  lifetime == OperandLifeTime::NO_VALUE;
+
706 }
+
707 
+
708 bool IsWeightsValid(const Operation& operation, uint32_t inputIndex, const Model& model);
+
709 
+ +
711  const Model& model,
+
712  const ConversionData& data,
+
713  const armnn::PermutationVector& dimensionMappings = g_DontPermute,
+
714  const armnn::TensorShape* overrideTensorShape = nullptr,
+
715  bool optional = false,
+
716  const armnn::DataType* overrideDataType = nullptr);
+
717 
+ +
719  const Operation& operation,
+
720  uint32_t inputIndex,
+
721  const Model& model,
+
722  const ConversionData& data,
+
723  const armnn::PermutationVector& dimensionMappings = g_DontPermute,
+
724  const armnn::TensorShape* overrideTensorShape = nullptr,
+
725  bool optional = false)
+
726 {
+
727  const Operand* operand = GetInputOperand(operation, inputIndex, model);
+
728  if (!operand)
+
729  {
+
730  Fail("%s: failed to get input operand: index=%u", __func__, inputIndex);
+
731  return ConstTensorPin();
+
732  }
+
733  return ConvertOperandToConstTensorPin(*operand,
+
734  model,
+
735  data,
+
736  dimensionMappings,
+
737  overrideTensorShape,
+
738  optional);
+
739 }
+
740 
+
741 template <typename OutputType>
+
742 bool GetInputScalar(const Operation& operation,
+
743  uint32_t inputIndex,
+
744  OperandType type,
+
745  OutputType& outValue,
+
746  const Model& model,
+
747  const ConversionData& data,
+
748  bool optional = false)
+
749 {
+
750  const Operand* operand = GetInputOperand(operation, inputIndex, model);
+
751  if (!optional && !operand)
+
752  {
+
753  return Fail("%s: invalid input operand at index %i", __func__, inputIndex);
+
754  }
+
755 
+
756  if (!optional && operand->type != type)
+
757  {
+
758  VLOG(DRIVER) << __func__ << ": unexpected operand type: " << operand->type << " should be: " << type;
+
759  return false;
+
760  }
+
761 
+
762  if (!optional && operand->location.length != sizeof(OutputType))
+
763  {
+
764  return Fail("%s: incorrect operand location length: %i (should be %i)",
+
765  __func__, operand->location.length, sizeof(OutputType));
+
766  }
+
767 
+
768  const void* valueAddress = GetOperandValueReadOnlyAddress(*operand, model, data);
+
769  if (!optional && !valueAddress)
+
770  {
+
771  return Fail("%s: failed to get address for operand", __func__);
+
772  }
+
773 
+
774  if(!optional)
+
775  {
+
776  outValue = *(static_cast<const OutputType*>(valueAddress));
+
777  }
+
778 
+
779  return true;
+
780 }
+
781 
+
782 inline bool GetInputInt32(const Operation& operation,
+
783  uint32_t inputIndex,
+
784  int32_t& outValue,
+
785  const Model& model,
+
786  const ConversionData& data)
+
787 {
+
788  return GetInputScalar(operation, inputIndex, OperandType::INT32, outValue, model, data);
+
789 }
+
790 
+
791 inline bool GetInputFloat32(const Operation& operation,
+
792  uint32_t inputIndex,
+
793  float& outValue,
+
794  const Model& model,
+
795  const ConversionData& data)
+
796 {
+
797  return GetInputScalar(operation, inputIndex, OperandType::FLOAT32, outValue, model, data);
+
798 }
+
799 
+
800 inline bool GetInputActivationFunctionImpl(const Operation& operation,
+
801  uint32_t inputIndex,
+
802  OperandType type,
+
803  ActivationFn& outActivationFunction,
+
804  const Model& model,
+
805  const ConversionData& data)
+
806 {
+
807  if (type != OperandType::INT32 && type != OperandType::TENSOR_INT32)
+
808  {
+
809  VLOG(DRIVER) << __func__ << ": unexpected operand type: " << type
+
810  << " should be OperandType::INT32 or OperandType::TENSOR_INT32";
+
811  return false;
+
812  }
+
813 
+
814  int32_t activationFunctionAsInt;
+
815  if (!GetInputScalar(operation, inputIndex, type, activationFunctionAsInt, model, data))
+
816  {
+
817  return Fail("%s: failed to get activation input value", __func__);
+
818  }
+
819  outActivationFunction = static_cast<ActivationFn>(activationFunctionAsInt);
+
820  return true;
+
821 }
+
822 
+
823 inline bool GetInputActivationFunction(const Operation& operation,
+
824  uint32_t inputIndex,
+
825  ActivationFn& outActivationFunction,
+
826  const Model& model,
+
827  const ConversionData& data)
+
828 {
+
829  return GetInputActivationFunctionImpl(operation,
+
830  inputIndex,
+
831  OperandType::INT32,
+
832  outActivationFunction,
+
833  model,
+
834  data);
+
835 }
+
836 
+
837 inline bool GetInputActivationFunctionFromTensor(const Operation& operation,
+
838  uint32_t inputIndex,
+
839  ActivationFn& outActivationFunction,
+
840  const Model& model,
+
841  const ConversionData& data)
+
842 {
+
843  // This only accepts a 1-D tensor of size 1
+
844  return GetInputActivationFunctionImpl(operation,
+
845  inputIndex,
+
846  OperandType::INT32,
+
847  outActivationFunction,
+
848  model,
+
849  data);
+
850 }
+
851 
+
852 
+
853 inline bool GetOptionalInputActivation(const Operation& operation,
+
854  uint32_t inputIndex,
+
855  ActivationFn& activationFunction,
+
856  const Model& model,
+
857  const ConversionData& data)
+
858 {
+
859  if (operation.inputs.size() <= inputIndex)
+
860  {
+
861  activationFunction = ActivationFn::kActivationNone;
+
862  }
+
863  else
+
864  {
+
865  if (!GetInputActivationFunction(operation, inputIndex, activationFunction, model, data))
+
866  {
+
867  return Fail("%s: Operation has invalid inputs", __func__);
+
868  }
+
869  }
+
870  return true;
+
871 }
+
872 
+
873 template<typename ConvolutionDescriptor>
+ +
875  uint32_t dilationXIndex,
+
876  ConvolutionDescriptor& descriptor,
+
877  const Model& model,
+
878  const ConversionData& data)
+
879 {
+
880  bool success = true;
+
881  if (operation.inputs.size() >= dilationXIndex + 2)
+
882  {
+
883  success &= GetInputScalar(operation,
+
884  dilationXIndex,
+
885  OperandType::INT32,
+
886  descriptor.m_DilationX,
+
887  model,
+
888  data);
+
889  success &= GetInputScalar(operation,
+
890  dilationXIndex + 1,
+
891  OperandType::INT32,
+
892  descriptor.m_DilationY,
+
893  model,
+
894  data);
+
895  }
+
896 
+
897  return success;
+
898 }
+
899 
+
900 inline bool GetOptionalBool(const Operation& operation,
+
901  uint32_t inputIndex,
+
902  const Model& model,
+
903  const ConversionData& data)
+
904 {
+
905  const Operand* operand = GetInputOperand(operation, inputIndex, model);
+
906  if (!operand)
+
907  {
+
908  return false;
+
909  }
+
910 
+
911  if (!IsBool(*operand))
+
912  {
+
913  return false;
+
914  }
+
915 
+
916  const void* valueAddress = GetOperandValueReadOnlyAddress(*operand, model, data);
+
917  if (!valueAddress)
+
918  {
+
919  return false;
+
920  }
+
921 
+
922  return *(static_cast<const bool*>(valueAddress));
+
923 }
+
924 
+
925 bool GetTensorInt32Values(const Operand& operand,
+
926  std::vector<int32_t>& outValues,
+
927  const Model& model,
+
928  const ConversionData& data);
+
929 
+
930 bool GetInputPaddingScheme(const Operation& operation,
+
931  uint32_t inputIndex,
+
932  PaddingScheme& outPaddingScheme,
+
933  const Model& model,
+
934  const ConversionData& data);
+
935 
+ +
937  uint32_t inputIndex,
+
938  const Model& model,
+
939  ConversionData& data,
+
940  const armnn::PermutationVector& dimensionMappings = g_DontPermute,
+
941  const LayerInputHandle* inputHandle = nullptr);
+
942 
+
943 bool SetupAndTrackLayerOutputSlot(const Operation& operation,
+
944  uint32_t operationOutputIndex,
+ +
946  uint32_t layerOutputIndex,
+
947  const Model& model,
+
948  ConversionData& data,
+
949  const armnn::TensorInfo* overrideOutputInfo = nullptr,
+
950  const std::function <void (const armnn::TensorInfo&, bool&)>& validateFunc = nullptr,
+
951  const ActivationFn& activationFunction = ActivationFn::kActivationNone,
+
952  bool inferOutputShapes = false);
+
953 
+ +
955  uint32_t inputIndex,
+
956  const Model& model,
+
957  ConversionData& data);
+
958 
+ +
960  const Operation& operation,
+
961  uint32_t outputIndex,
+ +
963  const Model& model,
+
964  ConversionData& data,
+
965  const armnn::TensorInfo* overrideOutputInfo = nullptr,
+
966  const std::function <void (const armnn::TensorInfo&, bool&)>& validateFunc = nullptr,
+
967  const ActivationFn& activationFunction = ActivationFn::kActivationNone)
+
968 {
+
969  return SetupAndTrackLayerOutputSlot(operation,
+
970  outputIndex,
+
971  layer,
+
972  outputIndex,
+
973  model,
+
974  data,
+
975  overrideOutputInfo,
+
976  validateFunc,
+
977  activationFunction);
+
978 }
+
979 
+
980 bool ConvertToActivation(const Operation& operation,
+
981  const char* operationName,
+
982  const armnn::ActivationDescriptor& activationDesc,
+
983  const Model& model,
+
984  ConversionData& data);
+
985 
+
986 bool ConvertPaddings(const Operation& operation,
+
987  const Model& model,
+
988  ConversionData& data,
+
989  unsigned int rank,
+
990  armnn::PadDescriptor& padDescriptor);
+
991 bool ConvertReduce(const Operation& operation,
+
992  const Model& model,
+
993  ConversionData& data,
+
994  armnn::ReduceOperation reduceOperation);
+
995 
+
996 bool ConvertPooling2d(const Operation& operation,
+
997  const char* operationName,
+
998  armnn::PoolingAlgorithm poolType,
+
999  const Model& model,
+
1000  ConversionData& data);
+
1001 
+
1002 inline bool IsQSymm8(const Operand& operand)
+
1003 {
+
1004  return operand.type == OperandType::TENSOR_QUANT8_SYMM;
+
1005 }
+
1006 
+ +
1008 {
+
1009  SUCCESS,
+
1010  NOT_REQUIRED,
+ +
1012 };
+
1013 
+
1014 using DequantizeResult = std::tuple<std::unique_ptr<float[]>, size_t, armnn::TensorInfo, DequantizeStatus>;
+
1015 
+
1016 DequantizeResult DequantizeIfRequired(size_t operand_index,
+
1017  const Operation& operation,
+
1018  const Model& model,
+
1019  const ConversionData& data);
+
1020 
+ +
1022  const Model& model,
+
1023  const ConversionData& data,
+
1024  size_t operandIndex,
+
1025  bool optional = false);
+
1026 
+
1027 bool IsConnectedToDequantize(armnn::IOutputSlot* ioutputSlot);
+
1028 
+
1029 } // namespace armnn_driver
+
+
+
IConnectableLayer * AddReshapeLayer(const ReshapeDescriptor &reshapeDescriptor, const char *name=nullptr)
Adds a reshape layer to the network.
Definition: Network.cpp:468
+
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
+ +
armnn::IConnectableLayer * ProcessActivation(const armnn::TensorInfo &tensorInfo, ActivationFn activation, armnn::IConnectableLayer *prevLayer, ConversionData &data)
+
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:339
+
bool IsEqual(const PermutationVector &other) const
Definition: Types.hpp:360
+
virtual void SetBackendId(const BackendId &id)=0
Set the backend of the IConnectableLayer.
+
bool GetOptionalInputActivation(const Operation &operation, uint32_t inputIndex, ActivationFn &activationFunction, const Model &model, const ConversionData &data)
+
void SetQuantizationDim(const Optional< unsigned int > &quantizationDim)
Definition: Tensor.cpp:499
+
std::tuple< std::unique_ptr< float[]>, size_t, armnn::TensorInfo, DequantizeStatus > DequantizeResult
+
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:36
+
bool GetTensorInt32Values(const Operand &operand, std::vector< int32_t > &outValues, const Model &model, const ConversionData &data)
+ +
std::vector<::android::nn::RunTimePoolInfo > m_MemPools
+
DataLayout
Definition: Types.hpp:62
+
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:451
+
::android::nn::Operand Operand
+
bool ConvertPooling2d(const Operation &operation, const char *operationName, armnn::PoolingAlgorithm poolType, const Model &model, ConversionData &data)
+
void Connect(armnn::IInputSlot &inputSlot)
+
bool IsWeightsValid(const Operation &operation, uint32_t inputIndex, const Model &model)
Utility functions.
+
ConstTensorPin ConvertOperationInputToConstTensorPin(const Operation &operation, uint32_t inputIndex, const Model &model, const ConversionData &data, const armnn::PermutationVector &dimensionMappings=g_DontPermute, const armnn::TensorShape *overrideTensorShape=nullptr, bool optional=false)
+
ConstTensorPin ConvertOperandToConstTensorPin(const Operand &operand, const Model &model, const ConversionData &data, const armnn::PermutationVector &dimensionMappings, const armnn::TensorShape *overrideTensorShape, bool optional, const armnn::DataType *overrideDataType)
+
float GetQuantizationScale() const
Definition: Tensor.cpp:461
+ + +
LayerInputHandle ConvertToLayerInputHandle(const Operation &operation, uint32_t inputIndex, const Model &model, ConversionData &data, const armnn::PermutationVector &dimensionMappings, const LayerInputHandle *inputHandle)
+
::android::nn::Operand::LifeTime OperandLifeTime
+
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:195
+ +
bool GetOptionalBool(const Operation &operation, uint32_t inputIndex, const Model &model, const ConversionData &data)
+
#define FORWARD_LAYER_SUPPORT_FUNC(funcName, func, backends, supported, setBackend,...)
+
const Operand * GetOutputOperand(const Operation &operation, uint32_t outputIndex, const Model &model)
+
::android::nn::Operation Operation
+
bool ConvertToActivation(const Operation &operation, const char *operationName, const armnn::ActivationDescriptor &activationDesc, const Model &model, ConversionData &data)
+
void SanitizeQuantizationScale(LayerInputHandle &weight, LayerInputHandle &input)
+ +
virtual const TensorInfo & GetTensorInfo() const =0
+ +
armnn::DataLayout OptionalDataLayout(const Operation &operation, uint32_t inputIndex, const Model &model, ConversionData &data)
+ +
armnn::TensorShape TransposeTensorShape(const armnn::TensorShape &srcShape, const armnn::PermutationVector &mappings)
Definition: Transpose.cpp:98
+
const armnn::PermutationVector g_DontPermute
+
bool HasPerAxisQuantization() const
Definition: Tensor.cpp:446
+ + +
::android::nn::OperandType OperandType
+
ConversionData(const std::vector< armnn::BackendId > &backends)
+
bool GetInputPaddingScheme(const Operation &operation, uint32_t inputIndex, PaddingScheme &outPaddingScheme, const Model &model, const ConversionData &data)
+
IConnectableLayer * AddTransposeLayer(const TransposeDescriptor &transposeDescriptor, const char *name=nullptr)
Adds a transpose layer to the network.
Definition: Network.cpp:581
+ + + + +
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:473
+
void SetQuantizationScales(const std::vector< float > &scales)
Definition: Tensor.cpp:456
+
An output connection slot for a layer.
Definition: INetwork.hpp:53
+
bool ConvertPaddings(const Operation &operation, const Model &model, ConversionData &data, unsigned int rank, armnn::PadDescriptor &padDescriptor)
+
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
+
::android::nn::ErrorStatus ErrorStatus
+ +
Helper classes.
Definition: ArmnnDevice.cpp:37
+
A PadDescriptor for the PadLayer.
+
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
+
A TransposeDescriptor for the TransposeLayer.
+
::android::nn::Model Model
Helper classes.
+
DataType
Definition: Types.hpp:48
+
bool GetOperandType(const Operation &operation, uint32_t inputIndex, const Model &model, OperandType &type)
+
A ReshapeDescriptor for the ReshapeLayer.
+
bool GetInputInt32(const Operation &operation, uint32_t inputIndex, int32_t &outValue, const Model &model, const ConversionData &data)
+
bool GetOptionalConvolutionDilationParams(const Operation &operation, uint32_t dilationXIndex, ConvolutionDescriptor &descriptor, const Model &model, const ConversionData &data)
+
bool GetInputScalar(const Operation &operation, uint32_t inputIndex, OperandType type, OutputType &outValue, const Model &model, const ConversionData &data, bool optional=false)
+
bool within_percentage_tolerance(float a, float b, float tolerancePercent=1.0f)
Compare two floats and return true if their values are within a specified tolerance of each other.
+ + +
bool SetupAndTrackLayerOutputSlot(const Operation &operation, uint32_t operationOutputIndex, armnn::IConnectableLayer &layer, uint32_t layerOutputIndex, const Model &model, ConversionData &data, const armnn::TensorInfo *overrideOutputInfo, const std::function< void(const armnn::TensorInfo &, bool &)> &validateFunc, const ActivationFn &activationFunction, bool inferOutputShapes)
+
const armnn::ConstTensor & GetConstTensor() const
+ + +
bool GetInputActivationFunctionImpl(const Operation &operation, uint32_t inputIndex, OperandType type, ActivationFn &outActivationFunction, const Model &model, const ConversionData &data)
+
TensorShape m_TargetShape
Target shape value.
+
std::vector< armnn::IOutputSlot * > m_OutputSlotForOperand
+ +
armnn::IOutputSlot * GetOutputSlot() const
+ +
const Operand * GetInputOperand(const Operation &operation, uint32_t inputIndex, const Model &model, bool failOnIndexOutOfBounds=true)
+ +
::android::nn::OperationType OperationType
+
DequantizeResult DequantizeIfRequired(size_t operand_index, const Operation &operation, const Model &model, const ConversionData &data)
+
ConstTensorPin(bool optional=false)
+
void Disconnect(armnn::IInputSlot &inputSlot)
+ +
PermutationVector m_DimMappings
Indicates how to translate tensor elements from a given source into the target destination,...
+
bool IsQSymm8(const Operand &operand)
+
virtual int Connect(IInputSlot &destination)=0
+
const android::nn::Model::Subgraph & getMainModel(const android::nn::Model &model)
+
const TensorShape & GetShape() const
Definition: Tensor.hpp:191
+ +
bool IsOperandConstant(const Operand &operand)
+
const armnn::ConstTensor * GetConstTensorPtr() const
+ + +
bool GetInputActivationFunctionFromTensor(const Operation &operation, uint32_t inputIndex, ActivationFn &outActivationFunction, const Model &model, const ConversionData &data)
+ +
bool ConvertReduce(const Operation &operation, const Model &model, ConversionData &data, armnn::ReduceOperation reduceOperation)
+
void SetShape(const TensorShape &newShape)
Definition: Tensor.hpp:193
+
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
+
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
+ +
ReduceOperation
Definition: Types.hpp:156
+
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:327
+
const armnn::TensorInfo & GetTensorInfo() const
+
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:80
+
An input connection slot for a layer.
Definition: INetwork.hpp:25
+
PoolingAlgorithm
Definition: Types.hpp:149
+ + +
armnn::TensorInfo GetTensorInfo(unsigned int numberOfBatches, unsigned int numberOfChannels, unsigned int height, unsigned int width, const armnn::DataLayout dataLayout, const armnn::DataType dataType)
Definition: TensorUtils.cpp:38
+
ConstTensorPin DequantizeAndMakeConstTensorPin(const Operation &operation, const Model &model, const ConversionData &data, size_t operandIndex, bool optional)
+
bool GetInputActivationFunction(const Operation &operation, uint32_t inputIndex, ActivationFn &outActivationFunction, const Model &model, const ConversionData &data)
+
const void * GetOperandValueReadOnlyAddress(const Operand &operand, const Model &model, const ConversionData &data, bool optional)
+ +
unsigned int GetNumElements() const
Function that calculates the tensor elements by multiplying all dimension size which are Specified.
Definition: Tensor.cpp:181
+
const std::vector< armnn::BackendId > m_Backends
+
bool IsConnectedToDequantize(armnn::IOutputSlot *ioutputSlot)
+ +
bool GetInputFloat32(const Operation &operation, uint32_t inputIndex, float &outValue, const Model &model, const ConversionData &data)
+
Main network class which provides the interface for building up a neural network.
Definition: INetwork.hpp:347
+ + + + -- cgit v1.2.1