ArmNN
 22.05
Deserializer.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "Deserializer.hpp"
7 
8 #include <armnn/Descriptors.hpp>
9 #include <armnn/Exceptions.hpp>
10 #include <armnn/TypesUtils.hpp>
11 #include <armnn/LstmParams.hpp>
13 #include <armnn/Logging.hpp>
14 
15 #include <armnnUtils/Permute.hpp>
16 #include <armnnUtils/Transpose.hpp>
17 #include <armnn/utility/Assert.hpp>
20 
21 #include <ParserHelper.hpp>
22 #include <VerificationHelpers.hpp>
23 
24 #include <fmt/format.h>
25 
26 #include <fstream>
27 #include <algorithm>
28 #include <limits>
29 #include <numeric>
30 
32 using namespace armnn;
33 using namespace armnnSerializer;
34 
35 namespace armnnDeserializer
36 {
37 
38 IDeserializer::IDeserializer() : pDeserializerImpl(new DeserializerImpl()){}
39 
40 IDeserializer::~IDeserializer() = default;
41 
42 IDeserializer *IDeserializer::CreateRaw()
43 {
44  return new IDeserializer();
45 }
46 
47 IDeserializerPtr IDeserializer::Create()
48 {
49  return IDeserializerPtr(CreateRaw(), &IDeserializer::Destroy);
50 }
51 
52 void IDeserializer::Destroy(IDeserializer *parser)
53 {
54  delete parser;
55 }
56 
57 armnn::INetworkPtr IDeserializer::CreateNetworkFromBinary(const std::vector<uint8_t> &binaryContent)
58 {
59  return pDeserializerImpl->CreateNetworkFromBinary(binaryContent);
60 }
61 
62 armnn::INetworkPtr IDeserializer::CreateNetworkFromBinary(std::istream &binaryContent)
63 {
64  return pDeserializerImpl->CreateNetworkFromBinary(binaryContent);
65 }
66 
67 BindingPointInfo IDeserializer::GetNetworkInputBindingInfo(unsigned int layerId, const std::string &name) const
68 {
69  return pDeserializerImpl->GetNetworkInputBindingInfo(layerId, name);
70 }
71 
72 BindingPointInfo IDeserializer::GetNetworkOutputBindingInfo(unsigned int layerId, const std::string &name) const
73 {
74  return pDeserializerImpl->GetNetworkOutputBindingInfo(layerId, name);
75 }
76 
77 namespace
78 {
79 
80 const uint32_t VIRTUAL_LAYER_ID = std::numeric_limits<uint32_t>::max();
81 
82  void CheckGraph(const GraphPtr& graph,
83  unsigned int layersIndex,
84  const CheckLocation& location)
85 {
86  if (graph->layers() == nullptr)
87  {
88  throw ParseException(fmt::format("{0} was called with invalid (null) graph. "
89  "Possible reason is that the graph is not yet loaded and Unpack(ed). "
90  "layers:{1} at {2}",
91  location.m_Function,
92  layersIndex,
93  location.FileLine()));
94  }
95  else if (layersIndex >= graph->layers()->size())
96  {
97  throw ParseException(fmt::format("{0} was called with an invalid layers index. layers:{1} at {2}",
98  location.m_Function,
99  layersIndex,
100  location.FileLine()));
101  }
102 }
103 
104 void CheckLayers(const GraphPtr& graph,
105  unsigned int layersIndex,
106  unsigned int layerIndex,
107  const CheckLocation& location)
108 {
109  if (graph->layers() == nullptr)
110  {
111  throw ParseException(fmt::format("{0} was called with invalid (null) graph. "
112  "Possible reason is that the graph is not yet loaded and Unpack(ed). "
113  "layers:{1} at {2}",
114  location.m_Function,
115  layersIndex,
116  location.FileLine()));
117  }
118  else if (layersIndex >= graph->layers()->size())
119  {
120  throw ParseException(fmt::format("{0} was called with an invalid layers index. "
121  "layers:{1} at {2}",
122  location.m_Function,
123  layersIndex,
124  location.FileLine()));
125  }
126  else if (layerIndex >= graph->layers()[layersIndex].size()
127  && layerIndex != VIRTUAL_LAYER_ID)
128  {
129  throw ParseException(fmt::format("{0} was called with an invalid layer index. "
130  "layers:{1} layer:{2} at {3}",
131  location.m_Function,
132  layersIndex,
133  layerIndex,
134  location.FileLine()));
135  }
136 }
137 
138 void CheckTensorPtr(TensorRawPtr rawPtr,
139  const CheckLocation& location)
140 {
141  if (rawPtr == nullptr)
142  {
143  throw ParseException(fmt::format("{0} was called with a null tensor pointer. at {1}",
144  location.m_Function,
145  location.FileLine()));
146  }
147 }
148 
149 void CheckConstTensorPtr(ConstTensorRawPtr rawPtr,
150  const CheckLocation& location)
151 {
152  if (rawPtr == nullptr)
153  {
154  throw ParseException(fmt::format("{0} was called with a null const tensor pointer. at {1}",
155  location.m_Function,
156  location.FileLine()));
157  }
158 }
159 
160 void CheckConstTensorSize(const unsigned int constTensorSize,
161  const unsigned int tensorSize,
162  const CheckLocation& location)
163 {
164  if (constTensorSize != tensorSize)
165  {
166  throw ParseException(fmt::format("{0} wrong number of components supplied to tensor. at:{1}",
167  location.m_Function,
168  location.FileLine()));
169  }
170 }
171 
172 #define CHECK_TENSOR_PTR(TENSOR_PTR) \
173  CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
174 
175 #define CHECK_CONST_TENSOR_SIZE(CONST_TENSOR_SIZE, TENSOR_SIZE) \
176  CheckConstTensorSize(CONST_TENSOR_SIZE, TENSOR_SIZE, CHECK_LOCATION())
177 
178 #define CHECK_CONST_TENSOR_PTR(TENSOR_PTR) \
179  CheckConstTensorPtr(TENSOR_PTR, CHECK_LOCATION())
180 
181 #define CHECK_LAYERS(GRAPH, LAYERS_INDEX, LAYER_INDEX) \
182  CheckLayers(GRAPH, LAYERS_INDEX, LAYER_INDEX, CHECK_LOCATION())
183 
184 #define CHECK_GRAPH(GRAPH, LAYERS_INDEX) \
185  CheckGraph(GRAPH, LAYERS_INDEX, CHECK_LOCATION())
186 }
187 
188 bool CheckShape(const armnn::TensorShape& actual, const std::vector<uint32_t>& expected)
189 {
190  const unsigned int actualSize = actual.GetNumDimensions();
191  if (actualSize != expected.size())
192  {
193  return false;
194  }
195 
196  for (unsigned int i = 0u; i < actualSize; i++)
197  {
198  if (actual[i] != static_cast<unsigned int>(expected[i]))
199  {
200  return false;
201  }
202  }
203 
204  return true;
205 }
206 
207 IDeserializer::DeserializerImpl::DeserializerImpl()
208 : m_Network(nullptr, nullptr),
209 //May require LayerType_Max to be included
210 m_ParserFunctions(Layer_MAX+1, &IDeserializer::DeserializerImpl::ParseUnsupportedLayer)
211 {
212  // register supported layers
213  m_ParserFunctions[Layer_AbsLayer] = &DeserializerImpl::ParseAbs;
214  m_ParserFunctions[Layer_ActivationLayer] = &DeserializerImpl::ParseActivation;
215  m_ParserFunctions[Layer_AdditionLayer] = &DeserializerImpl::ParseAdd;
216  m_ParserFunctions[Layer_ArgMinMaxLayer] = &DeserializerImpl::ParseArgMinMax;
217  m_ParserFunctions[Layer_BatchToSpaceNdLayer] = &DeserializerImpl::ParseBatchToSpaceNd;
218  m_ParserFunctions[Layer_BatchNormalizationLayer] = &DeserializerImpl::ParseBatchNormalization;
219  m_ParserFunctions[Layer_CastLayer] = &DeserializerImpl::ParseCast;
220  m_ParserFunctions[Layer_ChannelShuffleLayer] = &DeserializerImpl::ParseChannelShuffle;
221  m_ParserFunctions[Layer_ComparisonLayer] = &DeserializerImpl::ParseComparison;
222  m_ParserFunctions[Layer_ConcatLayer] = &DeserializerImpl::ParseConcat;
223  m_ParserFunctions[Layer_ConstantLayer] = &DeserializerImpl::ParseConstant;
224  m_ParserFunctions[Layer_Convolution2dLayer] = &DeserializerImpl::ParseConvolution2d;
225  m_ParserFunctions[Layer_Convolution3dLayer] = &DeserializerImpl::ParseConvolution3d;
226  m_ParserFunctions[Layer_DepthToSpaceLayer] = &DeserializerImpl::ParseDepthToSpace;
227  m_ParserFunctions[Layer_DepthwiseConvolution2dLayer] = &DeserializerImpl::ParseDepthwiseConvolution2d;
228  m_ParserFunctions[Layer_DequantizeLayer] = &DeserializerImpl::ParseDequantize;
229  m_ParserFunctions[Layer_DetectionPostProcessLayer] = &DeserializerImpl::ParseDetectionPostProcess;
230  m_ParserFunctions[Layer_DivisionLayer] = &DeserializerImpl::ParseDivision;
231  m_ParserFunctions[Layer_ElementwiseUnaryLayer] = &DeserializerImpl::ParseElementwiseUnary;
232  m_ParserFunctions[Layer_EqualLayer] = &DeserializerImpl::ParseEqual;
233  m_ParserFunctions[Layer_FullyConnectedLayer] = &DeserializerImpl::ParseFullyConnected;
234  m_ParserFunctions[Layer_FillLayer] = &DeserializerImpl::ParseFill;
235  m_ParserFunctions[Layer_FloorLayer] = &DeserializerImpl::ParseFloor;
236  m_ParserFunctions[Layer_GatherLayer] = &DeserializerImpl::ParseGather;
237  m_ParserFunctions[Layer_GatherNdLayer] = &DeserializerImpl::ParseGatherNd;
238  m_ParserFunctions[Layer_GreaterLayer] = &DeserializerImpl::ParseGreater;
239  m_ParserFunctions[Layer_InstanceNormalizationLayer] = &DeserializerImpl::ParseInstanceNormalization;
240  m_ParserFunctions[Layer_L2NormalizationLayer] = &DeserializerImpl::ParseL2Normalization;
241  m_ParserFunctions[Layer_LogicalBinaryLayer] = &DeserializerImpl::ParseLogicalBinary;
242  m_ParserFunctions[Layer_LogSoftmaxLayer] = &DeserializerImpl::ParseLogSoftmax;
243  m_ParserFunctions[Layer_LstmLayer] = &DeserializerImpl::ParseLstm;
244  m_ParserFunctions[Layer_MaximumLayer] = &DeserializerImpl::ParseMaximum;
245  m_ParserFunctions[Layer_MeanLayer] = &DeserializerImpl::ParseMean;
246  m_ParserFunctions[Layer_MinimumLayer] = &DeserializerImpl::ParseMinimum;
247  m_ParserFunctions[Layer_MergeLayer] = &DeserializerImpl::ParseMerge;
248  m_ParserFunctions[Layer_MergerLayer] = &DeserializerImpl::ParseConcat;
249  m_ParserFunctions[Layer_MultiplicationLayer] = &DeserializerImpl::ParseMultiplication;
250  m_ParserFunctions[Layer_NormalizationLayer] = &DeserializerImpl::ParseNormalization;
251  m_ParserFunctions[Layer_PadLayer] = &DeserializerImpl::ParsePad;
252  m_ParserFunctions[Layer_PermuteLayer] = &DeserializerImpl::ParsePermute;
253  m_ParserFunctions[Layer_Pooling2dLayer] = &DeserializerImpl::ParsePooling2d;
254  m_ParserFunctions[Layer_Pooling3dLayer] = &DeserializerImpl::ParsePooling3d;
255  m_ParserFunctions[Layer_PreluLayer] = &DeserializerImpl::ParsePrelu;
256  m_ParserFunctions[Layer_QLstmLayer] = &DeserializerImpl::ParseQLstm;
257  m_ParserFunctions[Layer_QuantizeLayer] = &DeserializerImpl::ParseQuantize;
258  m_ParserFunctions[Layer_QuantizedLstmLayer] = &DeserializerImpl::ParseQuantizedLstm;
259  m_ParserFunctions[Layer_RankLayer] = &DeserializerImpl::ParseRank;
260  m_ParserFunctions[Layer_ReduceLayer] = &DeserializerImpl::ParseReduce;
261  m_ParserFunctions[Layer_ReshapeLayer] = &DeserializerImpl::ParseReshape;
262  m_ParserFunctions[Layer_ResizeBilinearLayer] = &DeserializerImpl::ParseResizeBilinear;
263  m_ParserFunctions[Layer_ResizeLayer] = &DeserializerImpl::ParseResize;
264  m_ParserFunctions[Layer_RsqrtLayer] = &DeserializerImpl::ParseRsqrt;
265  m_ParserFunctions[Layer_ShapeLayer] = &DeserializerImpl::ParseShape;
266  m_ParserFunctions[Layer_SliceLayer] = &DeserializerImpl::ParseSlice;
267  m_ParserFunctions[Layer_SoftmaxLayer] = &DeserializerImpl::ParseSoftmax;
268  m_ParserFunctions[Layer_SpaceToBatchNdLayer] = &DeserializerImpl::ParseSpaceToBatchNd;
269  m_ParserFunctions[Layer_SpaceToDepthLayer] = &DeserializerImpl::ParseSpaceToDepth;
270  m_ParserFunctions[Layer_SplitterLayer] = &DeserializerImpl::ParseSplitter;
271  m_ParserFunctions[Layer_StackLayer] = &DeserializerImpl::ParseStack;
272  m_ParserFunctions[Layer_StandInLayer] = &DeserializerImpl::ParseStandIn;
273  m_ParserFunctions[Layer_StridedSliceLayer] = &DeserializerImpl::ParseStridedSlice;
274  m_ParserFunctions[Layer_SubtractionLayer] = &DeserializerImpl::ParseSubtraction;
275  m_ParserFunctions[Layer_SwitchLayer] = &DeserializerImpl::ParseSwitch;
276  m_ParserFunctions[Layer_TransposeConvolution2dLayer] = &DeserializerImpl::ParseTransposeConvolution2d;
277  m_ParserFunctions[Layer_TransposeLayer] = &DeserializerImpl::ParseTranspose;
278  m_ParserFunctions[Layer_UnidirectionalSequenceLstmLayer] = &DeserializerImpl::ParseUnidirectionalSequenceLstm;
279 }
280 
282 {
283  auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type();
284 
285  switch(layerType)
286  {
288  return graphPtr->layers()->Get(layerIndex)->layer_as_AbsLayer()->base();
290  return graphPtr->layers()->Get(layerIndex)->layer_as_ActivationLayer()->base();
292  return graphPtr->layers()->Get(layerIndex)->layer_as_AdditionLayer()->base();
294  return graphPtr->layers()->Get(layerIndex)->layer_as_ArgMinMaxLayer()->base();
296  return graphPtr->layers()->Get(layerIndex)->layer_as_BatchToSpaceNdLayer()->base();
298  return graphPtr->layers()->Get(layerIndex)->layer_as_BatchNormalizationLayer()->base();
300  return graphPtr->layers()->Get(layerIndex)->layer_as_CastLayer()->base();
302  return graphPtr->layers()->Get(layerIndex)->layer_as_ChannelShuffleLayer()->base();
304  return graphPtr->layers()->Get(layerIndex)->layer_as_ComparisonLayer()->base();
306  return graphPtr->layers()->Get(layerIndex)->layer_as_ConcatLayer()->base();
308  return graphPtr->layers()->Get(layerIndex)->layer_as_ConstantLayer()->base();
310  return graphPtr->layers()->Get(layerIndex)->layer_as_Convolution2dLayer()->base();
312  return graphPtr->layers()->Get(layerIndex)->layer_as_Convolution3dLayer()->base();
314  return graphPtr->layers()->Get(layerIndex)->layer_as_DepthToSpaceLayer()->base();
316  return graphPtr->layers()->Get(layerIndex)->layer_as_DepthwiseConvolution2dLayer()->base();
318  return graphPtr->layers()->Get(layerIndex)->layer_as_DequantizeLayer()->base();
320  return graphPtr->layers()->Get(layerIndex)->layer_as_DetectionPostProcessLayer()->base();
322  return graphPtr->layers()->Get(layerIndex)->layer_as_DivisionLayer()->base();
324  return graphPtr->layers()->Get(layerIndex)->layer_as_EqualLayer()->base();
326  return graphPtr->layers()->Get(layerIndex)->layer_as_ElementwiseUnaryLayer()->base();
328  return graphPtr->layers()->Get(layerIndex)->layer_as_FullyConnectedLayer()->base();
330  return graphPtr->layers()->Get(layerIndex)->layer_as_FillLayer()->base();
332  return graphPtr->layers()->Get(layerIndex)->layer_as_FloorLayer()->base();
334  return graphPtr->layers()->Get(layerIndex)->layer_as_GatherLayer()->base();
336  return graphPtr->layers()->Get(layerIndex)->layer_as_GatherNdLayer()->base();
338  return graphPtr->layers()->Get(layerIndex)->layer_as_GreaterLayer()->base();
340  return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->base();
342  return graphPtr->layers()->Get(layerIndex)->layer_as_InstanceNormalizationLayer()->base();
344  return graphPtr->layers()->Get(layerIndex)->layer_as_L2NormalizationLayer()->base();
346  return graphPtr->layers()->Get(layerIndex)->layer_as_LogicalBinaryLayer()->base();
348  return graphPtr->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->base();
350  return graphPtr->layers()->Get(layerIndex)->layer_as_LstmLayer()->base();
352  return graphPtr->layers()->Get(layerIndex)->layer_as_MeanLayer()->base();
354  return graphPtr->layers()->Get(layerIndex)->layer_as_MinimumLayer()->base();
356  return graphPtr->layers()->Get(layerIndex)->layer_as_MaximumLayer()->base();
358  return graphPtr->layers()->Get(layerIndex)->layer_as_MergeLayer()->base();
360  return graphPtr->layers()->Get(layerIndex)->layer_as_MergerLayer()->base();
362  return graphPtr->layers()->Get(layerIndex)->layer_as_MultiplicationLayer()->base();
364  return graphPtr->layers()->Get(layerIndex)->layer_as_NormalizationLayer()->base();
366  return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->base();
368  return graphPtr->layers()->Get(layerIndex)->layer_as_PadLayer()->base();
370  return graphPtr->layers()->Get(layerIndex)->layer_as_PermuteLayer()->base();
372  return graphPtr->layers()->Get(layerIndex)->layer_as_Pooling2dLayer()->base();
374  return graphPtr->layers()->Get(layerIndex)->layer_as_Pooling3dLayer()->base();
376  return graphPtr->layers()->Get(layerIndex)->layer_as_PreluLayer()->base();
378  return graphPtr->layers()->Get(layerIndex)->layer_as_QLstmLayer()->base();
380  return graphPtr->layers()->Get(layerIndex)->layer_as_QuantizeLayer()->base();
382  return graphPtr->layers()->Get(layerIndex)->layer_as_QuantizedLstmLayer()->base();
384  return graphPtr->layers()->Get(layerIndex)->layer_as_RankLayer()->base();
386  return graphPtr->layers()->Get(layerIndex)->layer_as_ReduceLayer()->base();
388  return graphPtr->layers()->Get(layerIndex)->layer_as_ReshapeLayer()->base();
390  return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeBilinearLayer()->base();
392  return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeLayer()->base();
394  return graphPtr->layers()->Get(layerIndex)->layer_as_RsqrtLayer()->base();
396  return graphPtr->layers()->Get(layerIndex)->layer_as_ShapeLayer()->base();
398  return graphPtr->layers()->Get(layerIndex)->layer_as_SliceLayer()->base();
400  return graphPtr->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->base();
402  return graphPtr->layers()->Get(layerIndex)->layer_as_SpaceToBatchNdLayer()->base();
404  return graphPtr->layers()->Get(layerIndex)->layer_as_SpaceToDepthLayer()->base();
406  return graphPtr->layers()->Get(layerIndex)->layer_as_SplitterLayer()->base();
408  return graphPtr->layers()->Get(layerIndex)->layer_as_StackLayer()->base();
410  return graphPtr->layers()->Get(layerIndex)->layer_as_StandInLayer()->base();
412  return graphPtr->layers()->Get(layerIndex)->layer_as_StridedSliceLayer()->base();
414  return graphPtr->layers()->Get(layerIndex)->layer_as_SubtractionLayer()->base();
416  return graphPtr->layers()->Get(layerIndex)->layer_as_SwitchLayer()->base();
418  return graphPtr->layers()->Get(layerIndex)->layer_as_TransposeConvolution2dLayer()->base();
420  return graphPtr->layers()->Get(layerIndex)->layer_as_TransposeLayer()->base();
422  return graphPtr->layers()->Get(layerIndex)->layer_as_UnidirectionalSequenceLstmLayer()->base();
423  case Layer::Layer_NONE:
424  default:
425  throw ParseException(fmt::format("Layer type {} not recognized", layerType));
426  }
427 }
428 
429 std::string IDeserializer::DeserializerImpl::GetLayerName(const GraphPtr& graph, unsigned int index)
430 {
431  auto layer = GetBaseLayer(graph, index);
432  assert(layer);
433  return layer->layerName()->str();
434 }
435 
436 int32_t IDeserializer::DeserializerImpl::GetBindingLayerInfo(const GraphPtr& graphPtr, unsigned int layerIndex)
437 {
438  auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type();
439 
440  if (layerType == Layer::Layer_InputLayer)
441  {
442  return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->layerBindingId();
443  }
444  else if ( layerType == Layer::Layer_OutputLayer )
445  {
446  return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->layerBindingId();
447  }
448  return 0;
449 }
450 
452 {
453  switch (dataLayout)
454  {
462  default:
464  }
465 }
466 
468 {
469  switch (function)
470  {
493  default:
495  }
496 }
497 
499 {
500  switch (function)
501  {
505  default:
507  }
508 }
509 
511 {
512  switch (operation)
513  {
525  default:
527  }
528 }
529 
531 {
532  switch (operation)
533  {
544  default:
546  }
547 }
548 
550 {
551  switch (operation)
552  {
557  default:
558  throw armnn::InvalidArgumentException("Logical Binary operation unknown");
559  }
560 }
561 
563 {
564  switch (operation)
565  {
582  default:
583  throw armnn::InvalidArgumentException("Unary operation unknown");
584  }
585 }
586 
588 {
589  switch (paddingMode)
590  {
595  default:
597  }
598 }
599 
601 {
602  switch (method)
603  {
608  default:
610  }
611 }
612 
614 {
615  armnn::DataType type;
616  CHECK_TENSOR_PTR(tensorPtr);
617 
618  switch (tensorPtr->dataType())
619  {
620  case DataType_QAsymmS8:
622  break;
623  case DataType_QSymmS8:
625  break;
627  case DataType_QAsymmU8:
629  break;
630  case DataType_QSymmS16:
633  break;
634  case DataType_Signed32:
636  break;
637  case DataType_Signed64:
639  break;
640  case DataType_Float32:
642  break;
643  case DataType_Float16:
645  break;
646  case DataType_Boolean:
648  break;
649  default:
650  {
651  CheckLocation location = CHECK_LOCATION();
652  throw ParseException(fmt::format("Unsupported data type {0} = {1}. {2}",
653  tensorPtr->dataType(),
654  EnumNameDataType(tensorPtr->dataType()),
655  location.AsString()));
656  }
657  }
658 
659  float quantizationScale = tensorPtr->quantizationScale();
660  int32_t quantizationOffset = tensorPtr->quantizationOffset();
661 
662  if (tensorPtr->dimensionality() == static_cast<unsigned int>(Dimensionality::Scalar))
663  {
665  type,
666  quantizationScale,
667  quantizationOffset);
668  }
669  else if (tensorPtr->dimensionality() == static_cast<unsigned int>(Dimensionality::NotSpecified))
670  {
671  armnn::TensorInfo result(TensorShape{Dimensionality::NotSpecified},
672  type,
673  quantizationScale,
674  quantizationOffset);
675  return result;
676  }
677 
678  auto dimensions = tensorPtr->dimensions();
679  unsigned int size = dimensions->size();
680  std::vector<unsigned int> outputDims(dimensions->begin(), dimensions->begin() + size);
681  bool dimensionsSpecificity[armnn::MaxNumOfTensorDimensions];
682  std::fill_n(dimensionsSpecificity, armnn::MaxNumOfTensorDimensions, true);
683  // For backwards compatibility check if the dimensionSpecificity vector is present first.
684  // The default is to have dimensionSpecificity set to all true's anyway.
685  if (tensorPtr->dimensionSpecificity() != nullptr)
686  {
687  auto dimensionSpecificity = tensorPtr->dimensionSpecificity();
688  size = dimensionSpecificity->size();
689  for (unsigned int i = 0; i < size; ++i)
690  {
691  dimensionsSpecificity[i] = dimensionSpecificity->Get(i);
692  }
693  }
694  // Construct a TensorShape
695  TensorShape shape(size, outputDims.data(), dimensionsSpecificity);
696 
697  auto quantizationScales = tensorPtr->quantizationScales();
698  if (quantizationScales)
699  {
700  unsigned int quantizationScalesSize = quantizationScales->size();
701  std::vector<float> scales(quantizationScales->begin(), quantizationScales->begin() + quantizationScalesSize);
702  unsigned int quantizationDim = tensorPtr->quantizationDim();
703  armnn::TensorInfo result(shape,
704  type,
705  scales,
706  quantizationDim);
707  return result;
708  }
709 
710  // two statements (on purpose) for easier debugging:
711  armnn::TensorInfo result(shape,
712  type,
713  quantizationScale,
714  quantizationOffset);
715 
716  return result;
717 }
718 
720 {
721  CHECK_CONST_TENSOR_PTR(constTensorPtr);
722  armnn::TensorInfo tensorInfo = ToTensorInfo(constTensorPtr->info());
723  tensorInfo.SetConstant();
724 
725  switch (constTensorPtr->data_type())
726  {
728  {
729  auto byteData = constTensorPtr->data_as_ByteData()->data();
730  CHECK_CONST_TENSOR_SIZE(byteData->size(), tensorInfo.GetNumElements());
731  return armnn::ConstTensor(tensorInfo, byteData->data());
732  }
734  {
735  auto shortData = constTensorPtr->data_as_ShortData()->data();
736  CHECK_CONST_TENSOR_SIZE(shortData->size(), tensorInfo.GetNumElements());
737  return armnn::ConstTensor(tensorInfo, shortData->data());
738  }
740  {
741  auto intData = constTensorPtr->data_as_IntData()->data();
742  CHECK_CONST_TENSOR_SIZE(intData->size(), tensorInfo.GetNumElements());
743  return armnn::ConstTensor(tensorInfo, intData->data());
744  }
746  {
747  auto longData = constTensorPtr->data_as_LongData()->data();
748  CHECK_CONST_TENSOR_SIZE(longData->size(), tensorInfo.GetNumElements());
749  return armnn::ConstTensor(tensorInfo, longData->data());
750  }
751  default:
752  {
753  CheckLocation location = CHECK_LOCATION();
754  throw ParseException(fmt::format("Unsupported data type {0} = {1}. {2}",
755  constTensorPtr->data_type(),
756  EnumNameConstTensorData(constTensorPtr->data_type()),
757  location.AsString()));
758  }
759  }
760 }
761 
763 {
764  CHECK_LAYERS(graphPtr, 0, layerIndex);
765  auto layer = GetBaseLayer(graphPtr, layerIndex);
766  const auto& numInputs = layer->inputSlots()->size();
767 
768  TensorRawPtrVector result(numInputs);
769 
770  for (unsigned int i=0; i<numInputs; ++i)
771  {
772  auto inputId = CHECKED_NON_NEGATIVE(static_cast<int32_t>
773  (layer->inputSlots()->Get(i)->connection()->sourceLayerIndex()));
774  result[i] = GetBaseLayer(graphPtr, inputId)->outputSlots()->Get(0)->tensorInfo();
775  }
776  return result;
777 }
778 
780 {
781  CHECK_LAYERS(graphPtr, 0, layerIndex);
782  auto layer = GetBaseLayer(graphPtr, layerIndex);
783  const auto& numOutputs = layer->outputSlots()->size();
784 
785  TensorRawPtrVector result(numOutputs);
786 
787  for (unsigned int i=0; i<numOutputs; ++i)
788  {
789  result[i] = layer->outputSlots()->Get(i)->tensorInfo();
790  }
791  return result;
792 }
793 
794 void IDeserializer::DeserializerImpl::ParseUnsupportedLayer(GraphPtr graph, unsigned int layerIndex)
795 {
796  CHECK_LAYERS(graph, 0, layerIndex);
797  const auto layerName = GetBaseLayer(graph, layerIndex)->layerName()->c_str();
798  throw ParseException(fmt::format("Layer not supported. layerIndex: {0} "
799  "layerName: {1} / {2}",
800  layerIndex,
801  layerName,
802  CHECK_LOCATION().AsString()));
803 }
804 
805 void IDeserializer::DeserializerImpl::ResetParser()
806 {
807  m_Network = armnn::INetworkPtr(nullptr, nullptr);
808  m_InputBindings.clear();
809  m_OutputBindings.clear();
810 }
811 
812 
814 {
815  ResetParser();
816  GraphPtr graph = LoadGraphFromBinary(binaryContent.data(), binaryContent.size());
817  return CreateNetworkFromGraph(graph);
818 }
819 
821 {
822  ResetParser();
823  if (binaryContent.fail()) {
824  ARMNN_LOG(error) << (std::string("Cannot read input"));
825  throw ParseException("Unable to read Input stream data");
826  }
827  binaryContent.seekg(0, std::ios::end);
828  const std::streamoff size = binaryContent.tellg();
829  std::vector<char> content(static_cast<size_t>(size));
830  binaryContent.seekg(0);
831  binaryContent.read(content.data(), static_cast<std::streamsize>(size));
832  GraphPtr graph = LoadGraphFromBinary(reinterpret_cast<uint8_t*>(content.data()), static_cast<size_t>(size));
833  return CreateNetworkFromGraph(graph);
834 }
835 
836 GraphPtr IDeserializer::DeserializerImpl::LoadGraphFromBinary(const uint8_t* binaryContent, size_t len)
837 {
838  if (binaryContent == nullptr)
839  {
840  throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
841  CHECK_LOCATION().AsString()));
842  }
843  flatbuffers::Verifier verifier(binaryContent, len);
844  if (verifier.VerifyBuffer<SerializedGraph>() == false)
845  {
846  throw ParseException(fmt::format("Buffer doesn't conform to the expected Armnn "
847  "flatbuffers format. size:{0} {1}",
848  len,
849  CHECK_LOCATION().AsString()));
850  }
851  return GetSerializedGraph(binaryContent);
852 }
853 
854 INetworkPtr IDeserializer::DeserializerImpl::CreateNetworkFromGraph(GraphPtr graph)
855 {
856  m_Network = INetwork::Create();
857  ARMNN_ASSERT(graph != nullptr);
858  unsigned int layerIndex = 0;
859  for (AnyLayer const* layer : *graph->layers())
860  {
861  if (layer->layer_type() != Layer_InputLayer &&
862  layer->layer_type() != Layer_OutputLayer)
863  {
864  // lookup and call the parser function
865  auto& parserFunction = m_ParserFunctions[layer->layer_type()];
866  (this->*parserFunction)(graph, layerIndex);
867  }
868  ++layerIndex;
869  }
870 
871  SetupInputLayers(graph);
872  SetupOutputLayers(graph);
873 
874  // establish the connections from the layer outputs to the inputs of the subsequent layers
875  for (auto&& graphIt : m_GraphConnections)
876  {
877  Connections& connections = graphIt.second;
878  for (auto&& outputIt : connections.outputSlots)
879  {
880  const unsigned int outputSlotIndex = outputIt.first;
881  IOutputSlot* outputSlot = outputIt.second;
882  if (connections.inputSlots.find(outputSlotIndex) != connections.inputSlots.end())
883  {
884  for (IInputSlot* inputSlot : connections.inputSlots[outputSlotIndex])
885  {
886  outputSlot->Connect(*inputSlot);
887  }
888  }
889  }
890  }
891 
892  return std::move(m_Network);
893 }
894 
896  const std::string& name) const
897 {
898  IgnoreUnused(layerIndex);
899  for (auto inputBinding : m_InputBindings)
900  {
901  if (inputBinding.first == name)
902  {
903  return inputBinding.second;
904  }
905  }
906  throw ParseException(fmt::format("No input binding found for layer:{0} / {1}",
907  name,
908  CHECK_LOCATION().AsString()));
909 }
910 
912  const std::string& name) const
913 {
914  IgnoreUnused(layerIndex);
915  for (auto outputBinding : m_OutputBindings)
916  {
917  if (outputBinding.first == name)
918  {
919  return outputBinding.second;
920  }
921  }
922  throw ParseException(fmt::format("No output binding found for layer:{0} / {1}",
923  name,
924  CHECK_LOCATION().AsString()));
925 }
926 
927 unsigned int IDeserializer::DeserializerImpl::GetInputLayerInVector(GraphPtr graph, int targetId)
928 {
929  for (unsigned int i = 0; i < graph->layers()->size(); i++)
930  {
931  auto layer = graph->layers()->Get(i);
932  if (layer->layer_type() == Layer::Layer_InputLayer)
933  {
934  auto layerBindingId = layer->layer_as_InputLayer()->base()->layerBindingId();
935  if (layerBindingId == targetId)
936  {
937  return i;
938  }
939  }
940  }
941  throw ParseException("Input layer with given layerBindingId not found");
942 }
943 
944 unsigned int IDeserializer::DeserializerImpl::GetOutputLayerInVector(GraphPtr graph, int targetId)
945 {
946  for (unsigned int i = 0; i < graph->layers()->size(); i++)
947  {
948  auto layer = graph->layers()->Get(i);
949  if (layer->layer_type() == Layer::Layer_OutputLayer)
950  {
951  auto layerBindingId = layer->layer_as_OutputLayer()->base()->layerBindingId();
952  if (layerBindingId == targetId)
953  {
954  return i;
955  }
956  }
957  }
958  throw ParseException("Output layer with given layerBindingId not found");
959 }
960 
961 unsigned int IDeserializer::DeserializerImpl::GetLayerIndexInVector(GraphPtr graph, unsigned int targetIndex)
962 {
963  for (unsigned int i = 0; i < graph->layers()->size(); i++)
964  {
965  LayerBaseRawPtr layer = GetBaseLayer(graph, i);
966  if (layer->index() == targetIndex)
967  {
968  return i;
969  }
970  }
971  throw ParseException("Layer with given index not found");
972 }
973 
974 IDeserializer::DeserializerImpl::FeatureVersions IDeserializer::DeserializerImpl::GetFeatureVersions(GraphPtr graph)
975 {
976  IDeserializer::DeserializerImpl::FeatureVersions versions;
977 
978  if (graph->featureVersions())
979  {
980  versions.m_BindingIdScheme = graph->featureVersions()->bindingIdsScheme();
981  versions.m_WeightsLayoutScheme = graph->featureVersions()->weightsLayoutScheme();
982  versions.m_ConstTensorsAsInputs = graph->featureVersions()->constantTensorsAsInputs();
983  }
984 
985  return versions;
986 }
987 
988 void IDeserializer::DeserializerImpl::SetupInputLayers(GraphPtr graph)
989 {
990  CHECK_GRAPH(graph, 0);
991  const unsigned int numInputs = graph->inputIds()->size();
992  m_InputBindings.clear();
993  m_InputBindings.reserve(numInputs);
994 
995  for (unsigned int i = 0; i < numInputs; i++)
996  {
997  unsigned int inputLayerIndex = 0xFFFFFFFF;
998  if (GetFeatureVersions(graph).m_BindingIdScheme == 0)
999  {
1000  const unsigned int inputId = armnn::numeric_cast<unsigned int>(graph->inputIds()->Get(i));
1001  inputLayerIndex = GetLayerIndexInVector(graph, inputId);
1002  }
1003  else
1004  {
1005  const int inputId = graph->inputIds()->Get(i);
1006  inputLayerIndex = GetInputLayerInVector(graph, inputId);
1007  }
1008 
1009  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, inputLayerIndex);
1010 
1011  // GetBindingLayerInfo expect the index to be index in the vector not index property on each layer base
1012  LayerBindingId bindingId = GetBindingLayerInfo(graph, inputLayerIndex);
1013  ARMNN_ASSERT_MSG(baseLayer->layerName()->c_str(), "Input has no name.");
1014 
1015  IConnectableLayer* inputLayer =
1016  m_Network->AddInputLayer(bindingId, baseLayer->layerName()->c_str());
1017 
1018  const armnn::TensorInfo& tensorInfo = ToTensorInfo(baseLayer->outputSlots()->Get(0)->tensorInfo());
1019  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1020  RegisterOutputSlots(graph, inputLayerIndex, inputLayer);
1021 
1022  BindingPointInfo bindingInfo = {bindingId, tensorInfo};
1023  m_InputBindings.push_back(std::make_pair(baseLayer->layerName()->c_str(), bindingInfo));
1024  }
1025 }
1026 
1027 void IDeserializer::DeserializerImpl::SetupOutputLayers(GraphPtr graph)
1028 {
1029  CHECK_GRAPH(graph, 0);
1030  const unsigned int numOutputs = graph->outputIds()->size();
1031  m_OutputBindings.clear();
1032  m_OutputBindings.reserve(numOutputs);
1033 
1034  for (unsigned int i = 0; i < numOutputs; i++)
1035  {
1036  unsigned int outputLayerIndex = 0xFFFFFFFF;
1037  if (GetFeatureVersions(graph).m_BindingIdScheme == 0)
1038  {
1039  const unsigned int outputId = armnn::numeric_cast<unsigned int>(graph->outputIds()->Get(i));
1040  outputLayerIndex = GetLayerIndexInVector(graph, outputId);
1041  }
1042  else
1043  {
1044  const int outputId = graph->outputIds()->Get(i);
1045  outputLayerIndex = GetOutputLayerInVector(graph, outputId);
1046  }
1047 
1048  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, outputLayerIndex);
1049 
1050  // GetBindingLayerInfo expect the index to be index in the vector not index property on each layer base
1051  LayerBindingId bindingId = GetBindingLayerInfo(graph, outputLayerIndex);
1052  ARMNN_ASSERT_MSG(baseLayer->layerName()->c_str(), "Output has no name.");
1053 
1054  IConnectableLayer* outputLayer =
1055  m_Network->AddOutputLayer(bindingId, baseLayer->layerName()->c_str());
1056 
1057  RegisterInputSlots(graph, outputLayerIndex, outputLayer);
1058  unsigned int sourceLayerIndex =
1059  GetLayerIndexInVector(graph, baseLayer->inputSlots()->Get(0)->connection()->sourceLayerIndex());
1060  unsigned int outputSlotIndex =
1061  GetLayerIndexInVector(graph, baseLayer->inputSlots()->Get(0)->connection()->outputSlotIndex());
1062  LayerBaseRawPtr sourceBaseLayer = GetBaseLayer(graph, sourceLayerIndex);
1063  const armnn::TensorInfo& tensorInfo = ToTensorInfo(
1064  sourceBaseLayer->outputSlots()->Get(outputSlotIndex)->tensorInfo());
1065  BindingPointInfo bindingInfo = {bindingId, tensorInfo};
1066  m_OutputBindings.push_back(std::make_pair(baseLayer->layerName()->c_str(), bindingInfo));
1067  }
1068 }
1069 
1070 void IDeserializer::DeserializerImpl::RegisterOutputSlots(GraphPtr graph,
1071  uint32_t layerIndex,
1072  IConnectableLayer* layer)
1073 {
1074  CHECK_LAYERS(graph, 0, layerIndex);
1075  ARMNN_ASSERT(layer != nullptr);
1076  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, layerIndex);
1077  if (baseLayer->outputSlots()->size() != layer->GetNumOutputSlots())
1078  {
1079  throw ParseException(fmt::format("The number of outputslots ({0}) does not match the number expected ({1})"
1080  " for layer index: {2} {3}",
1081  baseLayer->outputSlots()->size(),
1082  layer->GetNumOutputSlots(),
1083  layerIndex,
1084  CHECK_LOCATION().AsString()));
1085  }
1086 
1087  for (unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i)
1088  {
1089  const unsigned int slotIndex = baseLayer->outputSlots()->Get(i)->index();
1090  armnn::IOutputSlot* outputSlot = &(layer->GetOutputSlot(slotIndex));
1091  // layerIndex is not necessarily the same as baseLayer->index(). The latter is needed here
1092  RegisterOutputSlotOfConnection(baseLayer->index(), slotIndex, outputSlot);
1093  }
1094 }
1095 
1096 void IDeserializer::DeserializerImpl::RegisterInputSlots(GraphPtr graph,
1097  uint32_t layerIndex,
1098  armnn::IConnectableLayer* layer,
1099  std::vector<unsigned int> ignoreSlots)
1100 {
1101  CHECK_LAYERS(graph, 0, layerIndex);
1102  ARMNN_ASSERT(layer != nullptr);
1103  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, layerIndex);
1104 
1105  if (baseLayer->inputSlots()->size() != (layer->GetNumInputSlots() - ignoreSlots.size()))
1106  {
1107  throw ParseException(fmt::format("The number of inputslots ({0}) does not match the number expected ({1})"
1108  " for layer index:{2} {3}",
1109  baseLayer->inputSlots()->size(),
1110  layer->GetNumInputSlots(),
1111  layerIndex,
1112  CHECK_LOCATION().AsString()));
1113  }
1114 
1115  for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
1116  {
1117  // Check if slot should be ignored.
1118  if (std::find(ignoreSlots.begin(), ignoreSlots.end(), i) == ignoreSlots.end())
1119  {
1120  auto fbInputSlot = baseLayer->inputSlots()->Get(i);
1121  auto fbConnection = fbInputSlot->connection();
1122  armnn::IInputSlot* inputSlot = &(layer->GetInputSlot(fbInputSlot->index()));
1123  RegisterInputSlotOfConnection(fbConnection->sourceLayerIndex(), fbConnection->outputSlotIndex(), inputSlot);
1124  }
1125  }
1126 }
1127 
1128 void IDeserializer::DeserializerImpl::RegisterInputSlotOfConnection(uint32_t sourceLayerIndex,
1129  uint32_t outputSlotIndex,
1130  armnn::IInputSlot* inputSlot)
1131 {
1132  if (m_GraphConnections.find(sourceLayerIndex) == m_GraphConnections.end())
1133  {
1134  m_GraphConnections[sourceLayerIndex] = Connections();
1135  }
1136 
1137  Connections& connections = m_GraphConnections[sourceLayerIndex];
1138  if (connections.inputSlots.find(outputSlotIndex) == connections.inputSlots.end())
1139  {
1140  connections.inputSlots[outputSlotIndex] = {inputSlot};
1141  }
1142  else
1143  {
1144  connections.inputSlots[outputSlotIndex].push_back(inputSlot);
1145  }
1146 }
1147 
1148 void IDeserializer::DeserializerImpl::RegisterOutputSlotOfConnection(uint32_t sourceLayerIndex,
1149  uint32_t outputSlotIndex,
1150  armnn::IOutputSlot* outputSlot)
1151 {
1152  if (m_GraphConnections.find(sourceLayerIndex) == m_GraphConnections.end())
1153  {
1154  m_GraphConnections[sourceLayerIndex] = Connections();
1155  }
1156 
1157  Connections& connections = m_GraphConnections[sourceLayerIndex];
1158  if (connections.outputSlots.find(outputSlotIndex) != connections.outputSlots.end())
1159  {
1160  throw ParseException("Same output slot index processed twice");
1161  }
1162 
1163  connections.outputSlots[outputSlotIndex] = outputSlot;
1164 }
1165 
1166 void IDeserializer::DeserializerImpl::ParseAbs(GraphPtr graph, unsigned int layerIndex)
1167 {
1168  CHECK_LAYERS(graph, 0, layerIndex);
1169  auto inputs = GetInputs(graph, layerIndex);
1170  CHECK_LOCATION();
1171  CHECK_VALID_SIZE(inputs.size(), 1);
1172 
1173  auto outputs = GetOutputs(graph, layerIndex);
1174  CHECK_VALID_SIZE(outputs.size(), 1);
1175 
1176  auto layerName = GetLayerName(graph, layerIndex);
1177 
1179  IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
1180  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1181  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1182 
1183  RegisterInputSlots(graph, layerIndex, layer);
1184  RegisterOutputSlots(graph, layerIndex, layer);
1185 }
1186 
1187 void IDeserializer::DeserializerImpl::ParseActivation(GraphPtr graph, unsigned int layerIndex)
1188 {
1189  CHECK_LAYERS(graph, 0, layerIndex);
1190  auto inputs = GetInputs(graph, layerIndex);
1191  CHECK_LOCATION();
1192  CHECK_VALID_SIZE(inputs.size(), 1);
1193 
1194  auto outputs = GetOutputs(graph, layerIndex);
1195  CHECK_VALID_SIZE(outputs.size(), 1);
1196 
1197  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ActivationLayer();
1198  auto layerName = GetLayerName(graph, layerIndex);
1199  auto serializerDescriptor = serializerLayer->descriptor();
1200 
1201  armnn::ActivationDescriptor descriptor;
1202  descriptor.m_Function = ToActivationFunction(serializerDescriptor->activationFunction());
1203  descriptor.m_A = serializerDescriptor->a();
1204  descriptor.m_B = serializerDescriptor->b();
1205 
1206  IConnectableLayer* layer = m_Network->AddActivationLayer(descriptor,
1207  layerName.c_str());
1208  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1209  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1210 
1211  RegisterInputSlots(graph, layerIndex, layer);
1212  RegisterOutputSlots(graph, layerIndex, layer);
1213 }
1214 
1215 void IDeserializer::DeserializerImpl::ParseAdd(GraphPtr graph, unsigned int layerIndex)
1216 {
1217  CHECK_LAYERS(graph, 0, layerIndex);
1218  auto inputs = GetInputs(graph, layerIndex);
1219  CHECK_LOCATION();
1220  CHECK_VALID_SIZE(inputs.size(), 2);
1221 
1222  auto outputs = GetOutputs(graph, layerIndex);
1223  CHECK_VALID_SIZE(outputs.size(), 1);
1224 
1225  auto layerName = GetLayerName(graph, layerIndex);
1226  IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
1227 
1228  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1229  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1230 
1231  RegisterInputSlots(graph, layerIndex, layer);
1232  RegisterOutputSlots(graph, layerIndex, layer);
1233 }
1234 
1235 void IDeserializer::DeserializerImpl::ParseArgMinMax(GraphPtr graph, unsigned int layerIndex)
1236 {
1237  CHECK_LAYERS(graph, 0, layerIndex);
1238  auto inputs = GetInputs(graph, layerIndex);
1239  CHECK_LOCATION();
1240  CHECK_VALID_SIZE(inputs.size(), 1);
1241 
1242  auto outputs = GetOutputs(graph, layerIndex);
1243  CHECK_VALID_SIZE(outputs.size(), 1);
1244 
1245  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ArgMinMaxLayer();
1246  auto serializerDescriptor = serializerLayer->descriptor();
1247 
1248  armnn::ArgMinMaxDescriptor descriptor;
1249  descriptor.m_Function = ToArgMinMaxFunction(serializerDescriptor->argMinMaxFunction());
1250  descriptor.m_Axis = serializerDescriptor->axis();
1251  auto layerName = GetLayerName(graph, layerIndex);
1252  IConnectableLayer* layer = m_Network->AddArgMinMaxLayer(descriptor, layerName.c_str());
1253 
1254  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1255  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1256 
1257  RegisterInputSlots(graph, layerIndex, layer);
1258  RegisterOutputSlots(graph, layerIndex, layer);
1259 }
1260 
1261 void IDeserializer::DeserializerImpl::ParseBatchToSpaceNd(GraphPtr graph, unsigned int layerIndex)
1262 {
1263  CHECK_LAYERS(graph, 0, layerIndex);
1264 
1265  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
1266  CHECK_VALID_SIZE(inputs.size(), 1);
1267 
1268  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
1269  CHECK_VALID_SIZE(outputs.size(), 1);
1270 
1271  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_BatchToSpaceNdLayer()->descriptor();
1272  auto flatBufferCrops = flatBufferDescriptor->crops();
1273  auto flatBufferBlockShape = flatBufferDescriptor->blockShape();
1274 
1275  if (flatBufferCrops->Length() % 2 != 0)
1276  {
1277  throw ParseException(fmt::format("The size of crops must be divisible by 2 {}", CHECK_LOCATION().AsString()));
1278  }
1279 
1280  std::vector<std::pair<unsigned int, unsigned int>> crops;
1281  crops.reserve(flatBufferCrops->Length() / 2);
1282  for (unsigned int i = 0; i < flatBufferCrops->Length() - 1; i += 2)
1283  {
1284  crops.emplace_back(flatBufferCrops->Get(i), flatBufferCrops->Get(i+1));
1285  }
1286 
1288  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
1289  descriptor.m_BlockShape =
1290  std::vector<unsigned int>(flatBufferBlockShape->begin(), flatBufferBlockShape->end());
1291  descriptor.m_Crops = crops;
1292 
1293  auto layerName = GetLayerName(graph, layerIndex);
1294  IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(descriptor, layerName.c_str());
1295 
1296  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1297  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1298 
1299  RegisterInputSlots(graph, layerIndex, layer);
1300  RegisterOutputSlots(graph, layerIndex, layer);
1301 }
1302 
1303 void IDeserializer::DeserializerImpl::ParseBatchNormalization(GraphPtr graph, unsigned int layerIndex)
1304 {
1305  CHECK_LAYERS(graph, 0, layerIndex);
1306 
1307  auto inputs = GetInputs(graph, layerIndex);
1308  CHECK_VALID_SIZE(inputs.size(), 1);
1309 
1310  auto outputs = GetOutputs(graph, layerIndex);
1311  CHECK_VALID_SIZE(outputs.size(), 1);
1312  auto outputInfo = ToTensorInfo(outputs[0]);
1313 
1314  auto layerName = GetLayerName(graph, layerIndex);
1315 
1316  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_BatchNormalizationLayer();
1317  auto serializerDescriptor = serializerLayer->descriptor();
1318 
1320  descriptor.m_Eps = serializerDescriptor->eps();
1321  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
1322 
1323  armnn::ConstTensor mean = ToConstTensor(serializerLayer->mean());
1324  armnn::ConstTensor variance = ToConstTensor(serializerLayer->variance());
1325  armnn::ConstTensor beta = ToConstTensor(serializerLayer->beta());
1326  armnn::ConstTensor gamma = ToConstTensor(serializerLayer->gamma());
1327 
1328  IConnectableLayer* layer = m_Network->AddBatchNormalizationLayer(descriptor,
1329  mean,
1330  variance,
1331  beta,
1332  gamma,
1333  layerName.c_str());
1334  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1335 
1336  RegisterInputSlots(graph, layerIndex, layer);
1337  RegisterOutputSlots(graph, layerIndex, layer);
1338 }
1339 
1340 void IDeserializer::DeserializerImpl::ParseCast(GraphPtr graph, unsigned int layerIndex)
1341 {
1342  CHECK_LAYERS(graph, 0, layerIndex);
1343  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
1344  CHECK_LOCATION();
1345  CHECK_VALID_SIZE(inputs.size(), 1);
1346 
1347  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
1348  CHECK_VALID_SIZE(outputs.size(), 1);
1349 
1350  auto layerName = GetLayerName(graph, layerIndex);
1351 
1352  IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
1353 
1354  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1355  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1356 
1357  RegisterInputSlots(graph, layerIndex, layer);
1358  RegisterOutputSlots(graph, layerIndex, layer);
1359 }
1360 
1361 void IDeserializer::DeserializerImpl::ParseConstant(GraphPtr graph, unsigned int layerIndex)
1362 {
1363  CHECK_LAYERS(graph, 0, layerIndex);
1364  CHECK_LOCATION();
1365 
1366  auto outputs = GetOutputs(graph, layerIndex);
1367  CHECK_VALID_SIZE(outputs.size(), 1);
1368 
1369  auto layerName = GetLayerName(graph, layerIndex);
1370 
1371  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ConstantLayer();
1372  auto serializerInput = serializerLayer->input();
1373 
1374  armnn::ConstTensor input = ToConstTensor(serializerInput);
1375  IConnectableLayer* layer;
1376 
1377  // Required for when Constant Layer is used as an inputs to DepthwiseConvolution2d Layer.
1378  // Running a model that was created before weights layout scheme version was added to our flatbuffers
1379  // file ensuring older models can still be read and executed. featureVersion weights layout scheme 1
1380  // indicates a change in the depthwise weights layout within ArmNN from [M,I,H,W] --> [1,H,W,I*M]
1381  if (this->GetFeatureVersions(graph).m_WeightsLayoutScheme <= 0)
1382  {
1383  // Permute weights [ H, W, M, I ] --> [ 1, H, W, I*M ]
1384  // Step1: [ M, I, H, W ] --> [ H, W, I, M]
1385  PermutationVector permutationVector = { 3, 2, 0, 1 };
1386  armnn::TensorInfo weightsInfo = input.GetInfo();
1387  std::unique_ptr<unsigned char[]> permuteBuffer(new unsigned char[weightsInfo.GetNumBytes()]);
1388  weightsInfo = armnnUtils::Permuted(weightsInfo, permutationVector);
1389  armnnUtils::Permute(weightsInfo.GetShape(), permutationVector,
1390  input.GetMemoryArea(), permuteBuffer.get(),
1391  GetDataTypeSize(weightsInfo.GetDataType()));
1392 
1393  // Step2: Reshape [ H, W, I, M] --> [ 1, H, W, I*M ]
1394  auto weightsShape = weightsInfo.GetShape();
1395  weightsInfo.SetShape({1,
1396  weightsShape[0],
1397  weightsShape[1],
1398  weightsShape[2]*weightsShape[3]});
1399 
1400  armnn::ConstTensor weightsPermuted(weightsInfo, permuteBuffer.get());
1401 
1402  layer = m_Network->AddConstantLayer(weightsPermuted, layerName.c_str());
1403 
1404  layer->GetOutputSlot(0).SetTensorInfo(weightsPermuted.GetInfo());
1405 
1406  RegisterOutputSlots(graph, layerIndex, layer);
1407 
1408  return;
1409  }
1410  else
1411  {
1412  layer = m_Network->AddConstantLayer(input, layerName.c_str());
1413 
1414  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1415  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1416  }
1417 
1418  RegisterOutputSlots(graph, layerIndex, layer);
1419 }
1420 
1421 void IDeserializer::DeserializerImpl::ParseConvolution2d(GraphPtr graph, unsigned int layerIndex)
1422 {
1423  CHECK_LAYERS(graph, 0, layerIndex);
1424  auto inputs = GetInputs(graph, layerIndex);
1425  CHECK_LOCATION();
1426 
1427  auto outputs = GetOutputs(graph, layerIndex);
1428  CHECK_VALID_SIZE(outputs.size(), 1);
1429 
1430  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_Convolution2dLayer();
1431 
1432  auto layerName = GetLayerName(graph, layerIndex);
1433  auto flatbufferDescriptor = flatBufferLayer->descriptor();
1434 
1435  armnn::Convolution2dDescriptor descriptor;
1436  descriptor.m_PadLeft = flatbufferDescriptor->padLeft();
1437  descriptor.m_PadRight = flatbufferDescriptor->padRight();
1438  descriptor.m_PadTop = flatbufferDescriptor->padTop();
1439  descriptor.m_PadBottom = flatbufferDescriptor->padBottom();
1440  descriptor.m_StrideX = flatbufferDescriptor->strideX();
1441  descriptor.m_StrideY = flatbufferDescriptor->strideY();;
1442  descriptor.m_DilationX = flatbufferDescriptor->dilationX();
1443  descriptor.m_DilationY = flatbufferDescriptor->dilationY();;
1444  descriptor.m_BiasEnabled = flatbufferDescriptor->biasEnabled();;
1445  descriptor.m_DataLayout = ToDataLayout(flatbufferDescriptor->dataLayout());
1446 
1447  armnn::IConnectableLayer* layer;
1448  std::vector<unsigned int> ignoreSlots {};
1449 
1450  armnn::ConstTensor biasTensor;
1451  // Weights and biases used to be always constant and were stored as members of the layer. This has changed and
1452  // they are now passed as inputs. If they are constant then they will be stored in a ConstantLayer.
1453  if (this->GetFeatureVersions(graph).m_ConstTensorsAsInputs <= 0)
1454  {
1455  // If the model stores weights and biases as members of the layer we have to read them from there
1456  // but add them to their own ConstantLayer for compatibility
1457  CHECK_VALID_SIZE(inputs.size(), 1);
1458 
1459  layer = m_Network->AddConvolution2dLayer(descriptor,
1460  layerName.c_str());
1461 
1462  armnn::ConstTensor weightsTensor = ToConstTensor(flatBufferLayer->weights());
1463  auto weightsLayer = m_Network->AddConstantLayer(weightsTensor);
1464  weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u));
1465  weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsTensor.GetInfo());
1466  ignoreSlots.emplace_back(1u);
1467 
1468  if (descriptor.m_BiasEnabled)
1469  {
1470  biasTensor = ToConstTensor(flatBufferLayer->biases());
1471  auto biasLayer = m_Network->AddConstantLayer(biasTensor);
1472  biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u));
1473  biasLayer->GetOutputSlot(0).SetTensorInfo(biasTensor.GetInfo());
1474  ignoreSlots.emplace_back(2u);
1475  }
1476  }
1477  else
1478  {
1479  layer = m_Network->AddConvolution2dLayer(descriptor,
1480  layerName.c_str());
1481  uint32_t numInputs = descriptor.GetNumInputs();
1482  CHECK_VALID_SIZE(inputs.size(), numInputs);
1483  }
1484 
1485  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1486  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1487 
1488  RegisterInputSlots(graph, layerIndex, layer, ignoreSlots);
1489  RegisterOutputSlots(graph, layerIndex, layer);
1490 }
1491 
1492 void IDeserializer::DeserializerImpl::ParseConvolution3d(GraphPtr graph, unsigned int layerIndex)
1493 {
1494  CHECK_LAYERS(graph, 0, layerIndex);
1495  auto inputs = GetInputs(graph, layerIndex);
1496  CHECK_LOCATION();
1497 
1498  auto outputs = GetOutputs(graph, layerIndex);
1499  CHECK_VALID_SIZE(outputs.size(), 1);
1500 
1501  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_Convolution3dLayer();
1502  auto layerName = GetLayerName(graph, layerIndex);
1503  auto serializerDescriptor = serializerLayer->descriptor();
1504 
1505  armnn::Convolution3dDescriptor descriptor;
1506  descriptor.m_PadLeft = serializerDescriptor->padLeft();
1507  descriptor.m_PadRight = serializerDescriptor->padRight();
1508  descriptor.m_PadTop = serializerDescriptor->padTop();
1509  descriptor.m_PadBottom = serializerDescriptor->padBottom();
1510  descriptor.m_PadFront = serializerDescriptor->padFront();
1511  descriptor.m_PadBack = serializerDescriptor->padBack();
1512  descriptor.m_StrideX = serializerDescriptor->strideX();
1513  descriptor.m_StrideY = serializerDescriptor->strideY();
1514  descriptor.m_StrideZ = serializerDescriptor->strideZ();
1515  descriptor.m_DilationX = serializerDescriptor->dilationX();
1516  descriptor.m_DilationY = serializerDescriptor->dilationY();
1517  descriptor.m_DilationZ = serializerDescriptor->dilationZ();
1518  descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();
1519  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
1520 
1521  uint32_t numInputs = descriptor.GetNumInputs();
1522  CHECK_VALID_SIZE(inputs.size(), numInputs);
1523 
1524  IConnectableLayer* layer = m_Network->AddConvolution3dLayer(descriptor, layerName.c_str());
1525 
1526  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1527  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1528 
1529  RegisterInputSlots(graph, layerIndex, layer);
1530  RegisterOutputSlots(graph, layerIndex, layer);
1531 }
1532 
1533 void IDeserializer::DeserializerImpl::ParseDepthToSpace(GraphPtr graph, unsigned int layerIndex)
1534 {
1535  CHECK_LAYERS(graph, 0, layerIndex);
1536 
1537  auto inputs = GetInputs(graph, layerIndex);
1538  CHECK_VALID_SIZE(inputs.size(), 1);
1539 
1540  auto outputs = GetOutputs(graph, layerIndex);
1541  CHECK_VALID_SIZE(outputs.size(), 1);
1542 
1543  auto fbDescriptor = graph->layers()->Get(layerIndex)->layer_as_DepthToSpaceLayer()->descriptor();
1544 
1545  armnn::DepthToSpaceDescriptor descriptor;
1546  descriptor.m_BlockSize = fbDescriptor->blockSize();
1547  descriptor.m_DataLayout = ToDataLayout(fbDescriptor->dataLayout());
1548 
1549  auto layerName = GetLayerName(graph, layerIndex);
1550  IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
1551 
1552  armnn::TensorInfo outputInfo = ToTensorInfo(outputs[0]);
1553  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1554 
1555  RegisterInputSlots(graph, layerIndex, layer);
1556  RegisterOutputSlots(graph, layerIndex, layer);
1557 }
1558 
1559 void IDeserializer::DeserializerImpl::ParseDepthwiseConvolution2d(GraphPtr graph, unsigned int layerIndex)
1560 {
1561  CHECK_LAYERS(graph, 0, layerIndex);
1562  auto inputs = GetInputs(graph, layerIndex);
1563  CHECK_LOCATION();
1564 
1565  auto outputs = GetOutputs(graph, layerIndex);
1566  CHECK_VALID_SIZE(outputs.size(), 1);
1567 
1568  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_DepthwiseConvolution2dLayer();
1569  auto layerName = GetLayerName(graph, layerIndex);
1570  auto serializerDescriptor = serializerLayer->descriptor();
1571 
1573  descriptor.m_PadLeft = serializerDescriptor->padLeft();
1574  descriptor.m_PadRight = serializerDescriptor->padRight();
1575  descriptor.m_PadTop = serializerDescriptor->padTop();
1576  descriptor.m_PadBottom = serializerDescriptor->padBottom();
1577  descriptor.m_StrideX = serializerDescriptor->strideX();
1578  descriptor.m_StrideY = serializerDescriptor->strideY();
1579  descriptor.m_DilationX = serializerDescriptor->dilationX();
1580  descriptor.m_DilationY = serializerDescriptor->dilationY();
1581  descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();
1582  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
1583 
1584  IConnectableLayer* layer;
1585  std::vector<unsigned int> ignoreSlots {};
1586 
1587  // Weights and biases used to be always constant and were stored as members of the layer. This has changed and
1588  // they are now passed as inputs. If they are constant then they will be stored in a ConstantLayer.
1589  if (this->GetFeatureVersions(graph).m_ConstTensorsAsInputs <= 0)
1590  {
1591  CHECK_VALID_SIZE(inputs.size(), 1);
1592 
1593  // If the model stores weights and biases as members of the layer we have to read them from there
1594  // but add them to their own ConstantLayer for compatibility
1595  armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights());
1596  ignoreSlots.emplace_back(1u);
1597 
1598  layer = m_Network->AddDepthwiseConvolution2dLayer(descriptor,
1599  layerName.c_str());
1600 
1602  if (descriptor.m_BiasEnabled)
1603  {
1604  armnn::ConstTensor biases = ToConstTensor(serializerLayer->biases());
1605  ignoreSlots.emplace_back(2u);
1606 
1607  auto biasLayer = m_Network->AddConstantLayer(biases);
1608  biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u));
1609  biasLayer->GetOutputSlot(0).SetTensorInfo(biases.GetInfo());
1610  }
1611 
1612  if (this->GetFeatureVersions(graph).m_WeightsLayoutScheme <= 0)
1613  {
1614  // Permute weights [ H, W, M, I ] --> [ 1, H, W, I*M ]
1615  // Step1: [ M, I, H, W ] --> [ H, W, I, M]
1616  PermutationVector permutationVector = { 3, 2, 0, 1 };
1617  armnn::TensorInfo weightsInfo = weights.GetInfo();
1618  std::unique_ptr<unsigned char[]> permuteBuffer(new unsigned char[weightsInfo.GetNumBytes()]);
1619  weightsInfo = armnnUtils::Permuted(weightsInfo, permutationVector);
1620  armnnUtils::Permute(weightsInfo.GetShape(), permutationVector,
1621  weights.GetMemoryArea(), permuteBuffer.get(),
1622  GetDataTypeSize(weightsInfo.GetDataType()));
1623 
1624  // Step2: Reshape [ H, W, I, M] --> [ 1, H, W, I*M ]
1625  auto weightsShape = weightsInfo.GetShape();
1626  weightsInfo.SetShape({1,
1627  weightsShape[0],
1628  weightsShape[1],
1629  weightsShape[2]*weightsShape[3]});
1630 
1631  armnn::ConstTensor weightsPermuted(weightsInfo, permuteBuffer.get());
1632 
1633  auto weightsLayer = m_Network->AddConstantLayer(weightsPermuted);
1634  weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u));
1635  weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsPermuted.GetInfo());
1636  }
1637  else
1638  {
1639  auto weightsLayer = m_Network->AddConstantLayer(weights);
1640  weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u));
1641  weightsLayer->GetOutputSlot(0).SetTensorInfo(weights.GetInfo());
1642  }
1643  }
1644  else
1645  {
1646  layer = m_Network->AddDepthwiseConvolution2dLayer(descriptor,
1647  layerName.c_str());
1648  uint32_t numInputs = descriptor.GetNumInputs();
1649  CHECK_VALID_SIZE(inputs.size(), numInputs);
1650  }
1651 
1652  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1653  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1654 
1655  RegisterInputSlots(graph, layerIndex, layer, ignoreSlots);
1656  RegisterOutputSlots(graph, layerIndex, layer);
1657 }
1658 
1659 void IDeserializer::DeserializerImpl::ParseDetectionPostProcess(GraphPtr graph, unsigned int layerIndex)
1660 {
1661  CHECK_LAYERS(graph, 0, layerIndex);
1662  auto inputs = GetInputs(graph, layerIndex);
1663  CHECK_LOCATION();
1664  CHECK_VALID_SIZE(inputs.size(), 2);
1665 
1666  auto outputs = GetOutputs(graph, layerIndex);
1667  CHECK_VALID_SIZE(outputs.size(), 4);
1668 
1669  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_DetectionPostProcessLayer();
1670  auto layerName = GetLayerName(graph, layerIndex);
1671  auto flatBufferDescriptor = flatBufferLayer->descriptor();
1672 
1674  descriptor.m_MaxDetections = flatBufferDescriptor->maxDetections();
1675  descriptor.m_MaxClassesPerDetection = flatBufferDescriptor->maxClassesPerDetection();
1676  descriptor.m_DetectionsPerClass = flatBufferDescriptor->detectionsPerClass();
1677  descriptor.m_NmsScoreThreshold = flatBufferDescriptor->nmsScoreThreshold();
1678  descriptor.m_NmsIouThreshold = flatBufferDescriptor->nmsIouThreshold();
1679  descriptor.m_NumClasses = flatBufferDescriptor->numClasses();
1680  descriptor.m_UseRegularNms = flatBufferDescriptor->useRegularNms();
1681  descriptor.m_ScaleX = flatBufferDescriptor->scaleX();
1682  descriptor.m_ScaleY = flatBufferDescriptor->scaleY();
1683  descriptor.m_ScaleW = flatBufferDescriptor->scaleW();
1684  descriptor.m_ScaleH = flatBufferDescriptor->scaleH();
1685 
1686  armnn::ConstTensor anchors = ToConstTensor(flatBufferLayer->anchors());
1687 
1688  IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(descriptor,
1689  anchors,
1690  layerName.c_str());
1691 
1692  for (unsigned int i = 0; i < 4; i++)
1693  {
1694  layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i]));
1695  }
1696 
1697  RegisterInputSlots(graph, layerIndex, layer);
1698  RegisterOutputSlots(graph, layerIndex, layer);
1699 }
1700 
1701 void IDeserializer::DeserializerImpl::ParseDivision(GraphPtr graph, unsigned int layerIndex)
1702 {
1703  CHECK_LAYERS(graph, 0, layerIndex);
1704  auto inputs = GetInputs(graph, layerIndex);
1705  CHECK_LOCATION();
1706  CHECK_VALID_SIZE(inputs.size(), 2);
1707 
1708  auto outputs = GetOutputs(graph, layerIndex);
1709  CHECK_VALID_SIZE(outputs.size(), 1);
1710 
1711  auto layerName = GetLayerName(graph, layerIndex);
1712  IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
1713 
1714  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1715  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1716 
1717  RegisterInputSlots(graph, layerIndex, layer);
1718  RegisterOutputSlots(graph, layerIndex, layer);
1719 }
1720 
1721 void IDeserializer::DeserializerImpl::ParseEqual(GraphPtr graph, unsigned int layerIndex)
1722 {
1723  CHECK_LAYERS(graph, 0, layerIndex);
1724  auto inputs = GetInputs(graph, layerIndex);
1725  CHECK_LOCATION();
1726  CHECK_VALID_SIZE(inputs.size(), 2);
1727 
1728  auto outputs = GetOutputs(graph, layerIndex);
1729  CHECK_VALID_SIZE(outputs.size(), 1);
1730 
1731  auto layerName = GetLayerName(graph, layerIndex);
1733  IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str());
1734 
1735  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1736  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1737 
1738  RegisterInputSlots(graph, layerIndex, layer);
1739  RegisterOutputSlots(graph, layerIndex, layer);
1740 }
1741 
1742 void IDeserializer::DeserializerImpl::ParseFill(GraphPtr graph, unsigned int layerIndex)
1743 {
1744  CHECK_LAYERS(graph, 0, layerIndex);
1745  auto inputs = GetInputs(graph, layerIndex);
1746  CHECK_LOCATION();
1747  CHECK_VALID_SIZE(inputs.size(), 1);
1748 
1749  auto outputs = GetOutputs(graph, layerIndex);
1750  CHECK_VALID_SIZE(outputs.size(), 1);
1751 
1752  auto layerName = GetLayerName(graph, layerIndex);
1753  armnn::FillDescriptor descriptor;
1754  descriptor.m_Value = graph->layers()->Get(layerIndex)->layer_as_FillLayer()->descriptor()->value();
1755  IConnectableLayer* layer = m_Network->AddFillLayer(descriptor, layerName.c_str());
1756 
1757  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1758  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1759 
1760  RegisterInputSlots(graph, layerIndex, layer);
1761  RegisterOutputSlots(graph, layerIndex, layer);
1762 }
1763 
1764 void IDeserializer::DeserializerImpl::ParseGreater(GraphPtr graph, unsigned int layerIndex)
1765 {
1766  CHECK_LAYERS(graph, 0, layerIndex);
1767  auto inputs = GetInputs(graph, layerIndex);
1768  CHECK_LOCATION();
1769  CHECK_VALID_SIZE(inputs.size(), 2);
1770 
1771  auto outputs = GetOutputs(graph, layerIndex);
1772  CHECK_VALID_SIZE(outputs.size(), 1);
1773 
1774  auto layerName = GetLayerName(graph, layerIndex);
1776  IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str());
1777 
1778  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1779  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1780 
1781  RegisterInputSlots(graph, layerIndex, layer);
1782  RegisterOutputSlots(graph, layerIndex, layer);
1783 }
1784 
1785 void IDeserializer::DeserializerImpl::ParseInstanceNormalization(GraphPtr graph, unsigned int layerIndex)
1786 {
1787  CHECK_LAYERS(graph, 0, layerIndex);
1788 
1789  auto inputs = GetInputs(graph, layerIndex);
1790  CHECK_VALID_SIZE(inputs.size(), 1);
1791 
1792  auto outputs = GetOutputs(graph, layerIndex);
1793  CHECK_VALID_SIZE(outputs.size(), 1);
1794 
1795  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_InstanceNormalizationLayer();
1796  auto fbDescriptor = fbLayer->descriptor();
1797 
1799  descriptor.m_Gamma = fbDescriptor->gamma();
1800  descriptor.m_Beta = fbDescriptor->beta();
1801  descriptor.m_Eps = fbDescriptor->eps();
1802  descriptor.m_DataLayout = ToDataLayout(fbDescriptor->dataLayout());
1803 
1804  const std::string layerName = GetLayerName(graph, layerIndex);
1805  const armnn::TensorInfo outputInfo = ToTensorInfo(outputs[0]);
1806 
1807  IConnectableLayer* layer = m_Network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1808  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1809 
1810  RegisterInputSlots(graph, layerIndex, layer);
1811  RegisterOutputSlots(graph, layerIndex, layer);
1812 }
1813 
1814 void IDeserializer::DeserializerImpl::ParseL2Normalization(GraphPtr graph, unsigned int layerIndex)
1815 {
1816  CHECK_LAYERS(graph, 0, layerIndex);
1817 
1818  auto inputs = GetInputs(graph, layerIndex);
1819  CHECK_VALID_SIZE(inputs.size(), 1);
1820 
1821  auto outputs = GetOutputs(graph, layerIndex);
1822  CHECK_VALID_SIZE(outputs.size(), 1);
1823  auto outputInfo = ToTensorInfo(outputs[0]);
1824 
1825  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_L2NormalizationLayer();
1826  auto flatBufferDescriptor = flatBufferLayer->descriptor();
1827 
1828  auto layerName = GetLayerName(graph, layerIndex);
1830  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
1831  descriptor.m_Eps = flatBufferDescriptor->eps();
1832 
1833  IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(descriptor, layerName.c_str());
1834  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1835 
1836  RegisterInputSlots(graph, layerIndex, layer);
1837  RegisterOutputSlots(graph, layerIndex, layer);
1838 }
1839 
1840 void IDeserializer::DeserializerImpl::ParseLogicalBinary(GraphPtr graph, unsigned int layerIndex)
1841 {
1842  CHECK_LAYERS(graph, 0, layerIndex);
1843  CHECK_LOCATION();
1844 
1845  auto inputs = GetInputs(graph, layerIndex);
1846  CHECK_VALID_SIZE(inputs.size(), 2);
1847 
1848  auto outputs = GetOutputs(graph, layerIndex);
1849  CHECK_VALID_SIZE(outputs.size(), 1);
1850 
1851  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_LogicalBinaryLayer();
1852  auto fbDescriptor = fbLayer->descriptor();
1853 
1854  armnn::LogicalBinaryDescriptor descriptor;
1855  descriptor.m_Operation = ToLogicalBinaryOperation(fbDescriptor->operation());
1856 
1857  const std::string& layerName = GetLayerName(graph, layerIndex);
1858  IConnectableLayer* layer = m_Network->AddLogicalBinaryLayer(descriptor, layerName.c_str());
1859 
1860  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1861  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1862 
1863  RegisterInputSlots(graph, layerIndex, layer);
1864  RegisterOutputSlots(graph, layerIndex, layer);
1865 }
1866 
1867 void IDeserializer::DeserializerImpl::ParseLogSoftmax(GraphPtr graph, unsigned int layerIndex)
1868 {
1869  CHECK_LAYERS(graph, 0, layerIndex);
1870 
1871  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
1872  CHECK_VALID_SIZE(inputs.size(), 1);
1873 
1874  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
1875  CHECK_VALID_SIZE(outputs.size(), 1);
1876 
1877  armnn::LogSoftmaxDescriptor descriptor;
1878  descriptor.m_Beta = graph->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->descriptor()->beta();
1879  descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->descriptor()->axis();
1880  auto layerName = GetLayerName(graph, layerIndex);
1881 
1882  IConnectableLayer* layer = m_Network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
1883 
1884  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1885  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1886 
1887  RegisterInputSlots(graph, layerIndex, layer);
1888  RegisterOutputSlots(graph, layerIndex, layer);
1889 }
1890 
1891 void IDeserializer::DeserializerImpl::ParseMinimum(GraphPtr graph, unsigned int layerIndex)
1892 {
1893  CHECK_LAYERS(graph, 0, layerIndex);
1894  auto inputs = GetInputs(graph, layerIndex);
1895  CHECK_LOCATION();
1896  CHECK_VALID_SIZE(inputs.size(), 2);
1897 
1898  auto outputs = GetOutputs(graph, layerIndex);
1899  CHECK_VALID_SIZE(outputs.size(), 1);
1900 
1901  auto layerName = GetLayerName(graph, layerIndex);
1902  IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str());
1903 
1904  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1905  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1906 
1907  RegisterInputSlots(graph, layerIndex, layer);
1908  RegisterOutputSlots(graph, layerIndex, layer);
1909 }
1910 
1911 void IDeserializer::DeserializerImpl::ParseMaximum(GraphPtr graph, unsigned int layerIndex)
1912 {
1913  CHECK_LAYERS(graph, 0, layerIndex);
1914  auto inputs = GetInputs(graph, layerIndex);
1915  CHECK_LOCATION();
1916  CHECK_VALID_SIZE(inputs.size(), 2);
1917 
1918  auto outputs = GetOutputs(graph, layerIndex);
1919  CHECK_VALID_SIZE(outputs.size(), 1);
1920 
1921  auto layerName = GetLayerName(graph, layerIndex);
1922  IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str());
1923 
1924  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1925  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1926 
1927  RegisterInputSlots(graph, layerIndex, layer);
1928  RegisterOutputSlots(graph, layerIndex, layer);
1929 }
1930 
1931 const armnnSerializer::OriginsDescriptor* GetOriginsDescriptor(const armnnSerializer::SerializedGraph* graph,
1932  unsigned int layerIndex)
1933 {
1934  auto layerType = graph->layers()->Get(layerIndex)->layer_type();
1935 
1936  switch (layerType)
1937  {
1939  return graph->layers()->Get(layerIndex)->layer_as_ConcatLayer()->descriptor();
1941  return graph->layers()->Get(layerIndex)->layer_as_MergerLayer()->descriptor();
1942  default:
1943  throw armnn::Exception("unknown layer type, should be concat or merger");
1944  }
1945 }
1946 void IDeserializer::DeserializerImpl::ParseChannelShuffle(GraphPtr graph, unsigned int layerIndex)
1947 {
1948  CHECK_LAYERS(graph, 0, layerIndex);
1949 
1950  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
1951  CHECK_VALID_SIZE(inputs.size(), 1);
1952 
1953  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
1954  CHECK_VALID_SIZE(outputs.size(), 1);
1955 
1957  descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_ChannelShuffleLayer()->descriptor()->axis();
1958  descriptor.m_NumGroups =
1959  graph->layers()->Get(layerIndex)->layer_as_ChannelShuffleLayer()->descriptor()->numGroups();
1960 
1961  auto layerName = GetLayerName(graph, layerIndex);
1962  IConnectableLayer* layer = m_Network->AddChannelShuffleLayer(descriptor, layerName.c_str());
1963 
1964  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1965  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1966 
1967  RegisterInputSlots(graph, layerIndex, layer);
1968  RegisterOutputSlots(graph, layerIndex, layer);
1969 }
1970 void IDeserializer::DeserializerImpl::ParseComparison(GraphPtr graph, unsigned int layerIndex)
1971 {
1972  CHECK_LAYERS(graph, 0, layerIndex);
1973  CHECK_LOCATION();
1974 
1975  auto inputs = GetInputs(graph, layerIndex);
1976  CHECK_VALID_SIZE(inputs.size(), 2);
1977 
1978  auto outputs = GetOutputs(graph, layerIndex);
1979  CHECK_VALID_SIZE(outputs.size(), 1);
1980 
1981  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ComparisonLayer();
1982  auto fbDescriptor = fbLayer->descriptor();
1983 
1984  armnn::ComparisonDescriptor descriptor;
1985  descriptor.m_Operation = ToComparisonOperation(fbDescriptor->operation());
1986 
1987  const std::string& layerName = GetLayerName(graph, layerIndex);
1988  IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str());
1989 
1990  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1991  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1992 
1993  RegisterInputSlots(graph, layerIndex, layer);
1994  RegisterOutputSlots(graph, layerIndex, layer);
1995 }
1996 
1997 void IDeserializer::DeserializerImpl::ParseElementwiseUnary(GraphPtr graph, unsigned int layerIndex)
1998 {
1999  CHECK_LAYERS(graph, 0, layerIndex);
2000  CHECK_LOCATION();
2001 
2002  auto inputs = GetInputs(graph, layerIndex);
2003  CHECK_VALID_SIZE(inputs.size(), 1);
2004 
2005  auto outputs = GetOutputs(graph, layerIndex);
2006  CHECK_VALID_SIZE(outputs.size(), 1);
2007 
2008  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ElementwiseUnaryLayer();
2009  auto fbDescriptor = fbLayer->descriptor();
2010 
2012  descriptor.m_Operation = ToUnaryOperation(fbDescriptor->operation());
2013 
2014  const std::string& layerName = GetLayerName(graph, layerIndex);
2015  IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
2016 
2017  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2018  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2019 
2020  RegisterInputSlots(graph, layerIndex, layer);
2021  RegisterOutputSlots(graph, layerIndex, layer);
2022 }
2023 
2024 void IDeserializer::DeserializerImpl::ParseConcat(GraphPtr graph, unsigned int layerIndex)
2025 {
2026  CHECK_LAYERS(graph, 0, layerIndex);
2027  CHECK_LOCATION();
2028 
2029  auto outputs = GetOutputs(graph, layerIndex);
2030  CHECK_VALID_SIZE(outputs.size(), 1);
2031 
2032  auto layerName = GetLayerName(graph, layerIndex);
2033  auto originsDescriptor = GetOriginsDescriptor(graph, layerIndex);
2034  unsigned int numViews = originsDescriptor->numViews();
2035  unsigned int numDimensions = originsDescriptor->numDimensions();
2036 
2037  // can now check the number of inputs == number of views
2038  auto inputs = GetInputs(graph, layerIndex);
2039  CHECK_VALID_SIZE(inputs.size(), numViews);
2040 
2041  armnn::OriginsDescriptor descriptor(numViews, numDimensions);
2042  auto originsPtr = originsDescriptor->viewOrigins();
2043  for (unsigned int v = 0; v < numViews; ++v)
2044  {
2045  auto originPtr = originsPtr->Get(v);
2046  for (unsigned int d = 0; d < numDimensions; ++d)
2047  {
2048  uint32_t value = originPtr->data()->Get(d);
2049  descriptor.SetViewOriginCoord(v, d, value);
2050  }
2051  }
2052  descriptor.SetConcatAxis(originsDescriptor->concatAxis());
2053 
2054  IConnectableLayer* layer = m_Network->AddConcatLayer(descriptor, layerName.c_str());
2055  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2056  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2057 
2058  RegisterInputSlots(graph, layerIndex, layer);
2059  RegisterOutputSlots(graph, layerIndex, layer);
2060 }
2061 
2062 void IDeserializer::DeserializerImpl::ParseMultiplication(GraphPtr graph, unsigned int layerIndex)
2063 {
2064  CHECK_LAYERS(graph, 0, layerIndex);
2065  auto inputs = GetInputs(graph, layerIndex);
2066  CHECK_LOCATION();
2067  CHECK_VALID_SIZE(inputs.size(), 2);
2068 
2069  auto outputs = GetOutputs(graph, layerIndex);
2070  CHECK_VALID_SIZE(outputs.size(), 1);
2071 
2072  auto layerName = GetLayerName(graph, layerIndex);
2073  IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str());
2074 
2075  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2076  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2077 
2078  RegisterInputSlots(graph, layerIndex, layer);
2079  RegisterOutputSlots(graph, layerIndex, layer);
2080 }
2081 
2082 void IDeserializer::DeserializerImpl::ParseFloor(GraphPtr graph, unsigned int layerIndex)
2083 {
2084  CHECK_LAYERS(graph, 0, layerIndex);
2085  CHECK_LOCATION();
2086 
2087  auto inputs = GetInputs(graph, layerIndex);
2088  CHECK_VALID_SIZE(inputs.size(), 1);
2089 
2090  auto outputs = GetOutputs(graph, layerIndex);
2091  CHECK_VALID_SIZE(outputs.size(), 1);
2092 
2093  auto layerName = GetLayerName(graph, layerIndex);
2094 
2095  armnn::IConnectableLayer* layer;
2096 
2097  layer = m_Network->AddFloorLayer(layerName.c_str());
2098 
2099  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2100  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2101 
2102  RegisterInputSlots(graph, layerIndex, layer);
2103  RegisterOutputSlots(graph, layerIndex, layer);
2104 }
2105 
2106 void IDeserializer::DeserializerImpl::ParseFullyConnected(GraphPtr graph, unsigned int layerIndex)
2107 {
2108  CHECK_LAYERS(graph, 0, layerIndex);
2109  auto inputs = GetInputs(graph, layerIndex);
2110  CHECK_LOCATION();
2111 
2112  auto outputs = GetOutputs(graph, layerIndex);
2113  CHECK_VALID_SIZE(outputs.size(), 1);
2114 
2115  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_FullyConnectedLayer();
2116  auto layerName = GetLayerName(graph, layerIndex);
2117  auto flatBufferDescriptor = flatBufferLayer->descriptor();
2118 
2119  armnn::FullyConnectedDescriptor fullyConnectedDescriptor;
2120  fullyConnectedDescriptor.m_BiasEnabled = flatBufferDescriptor->biasEnabled();
2121  fullyConnectedDescriptor.m_TransposeWeightMatrix = flatBufferDescriptor->transposeWeightsMatrix();
2122  fullyConnectedDescriptor.m_ConstantWeights = flatBufferDescriptor->constantWeights();
2123 
2124  armnn::IConnectableLayer* layer;
2125  std::vector<unsigned int> ignoreSlots {};
2126 
2127  // Weights and biases used to be always constant and were stored as members of the layer. This has changed and
2128  // they are now passed as inputs. If they are constant then they will be stored in a ConstantLayer.
2129  if (this->GetFeatureVersions(graph).m_ConstTensorsAsInputs <= 0)
2130  {
2131  // If the model stores weights and biases as members of the layer we have to read them from there
2132  // but add them to their own ConstantLayer for compatibility
2133  CHECK_VALID_SIZE(inputs.size(), 1);
2134  layer = m_Network->AddFullyConnectedLayer(fullyConnectedDescriptor,
2135  layerName.c_str());
2136 
2137  armnn::ConstTensor weightsTensor = ToConstTensor(flatBufferLayer->weights());
2138  auto weightsLayer = m_Network->AddConstantLayer(weightsTensor);
2139  weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u));
2140  weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsTensor.GetInfo());
2141  ignoreSlots.emplace_back(1u);
2142 
2143  if (fullyConnectedDescriptor.m_BiasEnabled)
2144  {
2145  armnn::ConstTensor biasTensor = ToConstTensor(flatBufferLayer->biases());
2146  auto biasLayer = m_Network->AddConstantLayer(biasTensor);
2147  biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u));
2148  biasLayer->GetOutputSlot(0).SetTensorInfo(biasTensor.GetInfo());
2149  ignoreSlots.emplace_back(2u);
2150  }
2151  }
2152  else
2153  {
2154  layer = m_Network->AddFullyConnectedLayer(fullyConnectedDescriptor,
2155  layerName.c_str());
2156  uint32_t numInputs = fullyConnectedDescriptor.GetNumInputs();
2157  CHECK_VALID_SIZE(inputs.size(), numInputs);
2158  }
2159 
2160  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2161  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2162 
2163  RegisterInputSlots(graph, layerIndex, layer, ignoreSlots);
2164  RegisterOutputSlots(graph, layerIndex, layer);
2165 }
2166 
2167 void IDeserializer::DeserializerImpl::ParsePad(GraphPtr graph, unsigned int layerIndex)
2168 {
2169  CHECK_LAYERS(graph, 0, layerIndex);
2170 
2171  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2172  CHECK_VALID_SIZE(inputs.size(), 1);
2173 
2174  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2175  CHECK_VALID_SIZE(outputs.size(), 1);
2176 
2177  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_PadLayer()->descriptor();
2178  auto flatBufferPadList = flatBufferDescriptor->padList();
2179  auto paddingMode = flatBufferDescriptor->paddingMode();
2180  float padValue = flatBufferDescriptor->padValue();
2181 
2182  if (flatBufferPadList->Length() % 2 != 0)
2183  {
2184  throw ParseException(fmt::format("The size of the pad list must be divisible by 2 {}",
2185  CHECK_LOCATION().AsString()));
2186  }
2187 
2188  std::vector<std::pair<unsigned int, unsigned int>> padList;
2189  padList.reserve(flatBufferPadList->Length() / 2);
2190  for (unsigned int i = 0; i < flatBufferPadList->Length() - 1; i += 2)
2191  {
2192  padList.emplace_back(flatBufferPadList->Get(i), flatBufferPadList->Get(i+1));
2193  }
2194 
2195  armnn::PadDescriptor descriptor(padList, padValue, ToPaddingMode(paddingMode));
2196 
2197  auto layerName = GetLayerName(graph, layerIndex);
2198  IConnectableLayer* layer = m_Network->AddPadLayer(descriptor, layerName.c_str());
2199 
2200  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2201  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2202 
2203  RegisterInputSlots(graph, layerIndex, layer);
2204  RegisterOutputSlots(graph, layerIndex, layer);
2205 }
2206 
2207 void IDeserializer::DeserializerImpl::ParsePermute(GraphPtr graph, unsigned int layerIndex)
2208 {
2209  CHECK_LAYERS(graph, 0, layerIndex);
2210 
2211  auto dimsMapping =
2212  graph->layers()->Get(layerIndex)->layer_as_PermuteLayer()->descriptor()->dimMappings();
2213 
2214  auto inputs = GetInputs(graph, layerIndex);
2215  CHECK_VALID_SIZE(inputs.size(), 1);
2216 
2217  auto outputs = GetOutputs(graph, layerIndex);
2218  CHECK_VALID_SIZE(outputs.size(), 1);
2219  auto outputInfo = ToTensorInfo(outputs[0]);
2220 
2221  auto layerName = GetLayerName(graph, layerIndex);
2222  const armnn::PermuteDescriptor descriptor(armnn::PermutationVector(dimsMapping->data(), dimsMapping->Length()));
2223 
2224  IConnectableLayer* layer = m_Network->AddPermuteLayer(descriptor, layerName.c_str());
2225  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2226 
2227  RegisterInputSlots(graph, layerIndex, layer);
2228  RegisterOutputSlots(graph, layerIndex, layer);
2229 }
2230 
2232  unsigned int layerIndex)
2233 {
2234  IgnoreUnused(layerIndex);
2236 
2237  switch (pooling2dDesc->poolType())
2238  {
2240  {
2242  break;
2243  }
2244  case PoolingAlgorithm_Max:
2245  {
2247  break;
2248  }
2249  case PoolingAlgorithm_L2:
2250  {
2252  break;
2253  }
2254  default:
2255  {
2256  ARMNN_ASSERT_MSG(false, "Unsupported pooling algorithm");
2257  }
2258  }
2259 
2260  switch (pooling2dDesc->outputShapeRounding())
2261  {
2263  {
2265  break;
2266  }
2268  {
2270  break;
2271  }
2272  default:
2273  {
2274  ARMNN_ASSERT_MSG(false, "Unsupported output shape rounding");
2275  }
2276  }
2277 
2278  switch (pooling2dDesc->paddingMethod())
2279  {
2280  case PaddingMethod_Exclude:
2281  {
2283  break;
2284  }
2286  {
2288  break;
2289  }
2290  default:
2291  {
2292  ARMNN_ASSERT_MSG(false, "Unsupported padding method");
2293  }
2294  }
2295 
2296  switch (pooling2dDesc->dataLayout())
2297  {
2298  case DataLayout_NCHW:
2299  {
2301  break;
2302  }
2303  case DataLayout_NHWC:
2304  {
2306  break;
2307  }
2308  default:
2309  {
2310  ARMNN_ASSERT_MSG(false, "Unsupported data layout");
2311  }
2312  }
2313 
2314  desc.m_PadRight = pooling2dDesc->padRight();
2315  desc.m_PadLeft = pooling2dDesc->padLeft();
2316  desc.m_PadBottom = pooling2dDesc->padBottom();
2317  desc.m_PadTop = pooling2dDesc->padTop();
2318  desc.m_StrideX = pooling2dDesc->strideX();
2319  desc.m_StrideY = pooling2dDesc->strideY();
2320  desc.m_PoolWidth = pooling2dDesc->poolWidth();
2321  desc.m_PoolHeight = pooling2dDesc->poolHeight();
2322 
2323  return desc;
2324 }
2325 
2327  unsigned int layerIndex)
2328 {
2329  IgnoreUnused(layerIndex);
2331 
2332  switch (pooling3dDesc->poolType())
2333  {
2335  {
2337  break;
2338  }
2339  case PoolingAlgorithm_Max:
2340  {
2342  break;
2343  }
2344  case PoolingAlgorithm_L2:
2345  {
2347  break;
2348  }
2349  default:
2350  {
2351  ARMNN_ASSERT_MSG(false, "Unsupported pooling algorithm");
2352  }
2353  }
2354 
2355  switch (pooling3dDesc->outputShapeRounding())
2356  {
2358  {
2360  break;
2361  }
2363  {
2365  break;
2366  }
2367  default:
2368  {
2369  ARMNN_ASSERT_MSG(false, "Unsupported output shape rounding");
2370  }
2371  }
2372 
2373  switch (pooling3dDesc->paddingMethod())
2374  {
2375  case PaddingMethod_Exclude:
2376  {
2378  break;
2379  }
2381  {
2383  break;
2384  }
2385  default:
2386  {
2387  ARMNN_ASSERT_MSG(false, "Unsupported padding method");
2388  }
2389  }
2390 
2391  switch (pooling3dDesc->dataLayout())
2392  {
2393  case DataLayout_NCDHW:
2394  {
2396  break;
2397  }
2398  case DataLayout_NDHWC:
2399  {
2401  break;
2402  }
2403  default:
2404  {
2405  ARMNN_ASSERT_MSG(false, "Unsupported data layout");
2406  }
2407  }
2408 
2409  desc.m_PadRight = pooling3dDesc->padRight();
2410  desc.m_PadLeft = pooling3dDesc->padLeft();
2411  desc.m_PadBottom = pooling3dDesc->padBottom();
2412  desc.m_PadTop = pooling3dDesc->padTop();
2413  desc.m_PadFront = pooling3dDesc->padFront();
2414  desc.m_PadBack = pooling3dDesc->padBack();
2415  desc.m_StrideX = pooling3dDesc->strideX();
2416  desc.m_StrideY = pooling3dDesc->strideY();
2417  desc.m_StrideZ = pooling3dDesc->strideZ();
2418  desc.m_PoolWidth = pooling3dDesc->poolWidth();
2419  desc.m_PoolHeight = pooling3dDesc->poolHeight();
2420  desc.m_PoolDepth = pooling3dDesc->poolDepth();
2421 
2422  return desc;
2423 }
2424 
2425 void IDeserializer::DeserializerImpl::ParsePooling2d(GraphPtr graph, unsigned int layerIndex)
2426 {
2427  CHECK_LAYERS(graph, 0, layerIndex);
2428 
2429  auto pooling2dDes = graph->layers()->Get(layerIndex)->layer_as_Pooling2dLayer()->descriptor();
2430  auto inputs = GetInputs(graph, layerIndex);
2431  CHECK_VALID_SIZE(inputs.size(), 1);
2432 
2433  auto outputs = GetOutputs(graph, layerIndex);
2434  CHECK_VALID_SIZE(outputs.size(), 1);
2435  auto outputInfo = ToTensorInfo(outputs[0]);
2436 
2437  auto pooling2dDescriptor = GetPooling2dDescriptor(pooling2dDes, layerIndex);
2438  auto layerName = GetLayerName(graph, layerIndex);
2439  IConnectableLayer* layer = m_Network->AddPooling2dLayer(pooling2dDescriptor, layerName.c_str());
2440  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2441 
2442  RegisterInputSlots(graph, layerIndex, layer);
2443  RegisterOutputSlots(graph, layerIndex, layer);
2444 }
2445 
2446 void IDeserializer::DeserializerImpl::ParsePooling3d(GraphPtr graph, unsigned int layerIndex)
2447 {
2448  CHECK_LAYERS(graph, 0, layerIndex);
2449 
2450  auto pooling3dDes = graph->layers()->Get(layerIndex)->layer_as_Pooling3dLayer()->descriptor();
2451  auto inputs = GetInputs(graph, layerIndex);
2452  CHECK_VALID_SIZE(inputs.size(), 1);
2453 
2454  auto outputs = GetOutputs(graph, layerIndex);
2455  CHECK_VALID_SIZE(outputs.size(), 1);
2456  auto outputInfo = ToTensorInfo(outputs[0]);
2457 
2458  auto pooling3dDescriptor = GetPooling3dDescriptor(pooling3dDes, layerIndex);
2459  auto layerName = GetLayerName(graph, layerIndex);
2460  IConnectableLayer* layer = m_Network->AddPooling3dLayer(pooling3dDescriptor, layerName.c_str());
2461  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2462 
2463  RegisterInputSlots(graph, layerIndex, layer);
2464  RegisterOutputSlots(graph, layerIndex, layer);
2465 }
2466 
2467 void IDeserializer::DeserializerImpl::ParseQuantize(GraphPtr graph, unsigned int layerIndex)
2468 {
2469  CHECK_LAYERS(graph, 0, layerIndex);
2470 
2471  auto inputs = GetInputs(graph, layerIndex);
2472  CHECK_VALID_SIZE(inputs.size(), 1);
2473 
2474  auto outputs = GetOutputs(graph, layerIndex);
2475  CHECK_VALID_SIZE(outputs.size(), 1);
2476  auto outputInfo = ToTensorInfo(outputs[0]);
2477 
2478  auto layerName = GetLayerName(graph, layerIndex);
2479  IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
2480  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2481 
2482  RegisterInputSlots(graph, layerIndex, layer);
2483  RegisterOutputSlots(graph, layerIndex, layer);
2484 }
2485 
2487  const std::vector<uint32_t>& targetDimsIn)
2488 {
2489  std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2490  const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2491 
2492  if (stretchDim != targetDimsIn.end())
2493  {
2494  if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2495  {
2496  throw ParseException(fmt::format("At most one component of shape can be -1 {}",
2497  CHECK_LOCATION().AsString()));
2498  }
2499 
2500  auto targetNumElements =
2501  armnn::numeric_cast<unsigned int>(
2502  std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2503 
2504  auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2505  outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2506  }
2507 
2508  TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2509 
2510  armnn::TensorInfo reshapeInfo = inputTensorInfo;
2511  reshapeInfo.SetShape(outputShape);
2512 
2513  return reshapeInfo;
2514 }
2515 
2516 void IDeserializer::DeserializerImpl::ParseRank(GraphPtr graph, unsigned int layerIndex)
2517 {
2518  CHECK_LAYERS(graph, 0, layerIndex);
2519 
2520  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2521  CHECK_VALID_SIZE(inputs.size(), 1);
2522 
2523  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2524  CHECK_VALID_SIZE(outputs.size(), 1);
2525 
2526  auto layerName = GetLayerName(graph, layerIndex);
2527  IConnectableLayer* layer = m_Network->AddRankLayer( layerName.c_str());
2528 
2529  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2530  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2531 
2532  RegisterInputSlots(graph, layerIndex, layer);
2533  RegisterOutputSlots(graph, layerIndex, layer);
2534 }
2535 
2536 void IDeserializer::DeserializerImpl::ParseReduce(GraphPtr graph, unsigned int layerIndex)
2537 {
2538  CHECK_LAYERS(graph, 0, layerIndex);
2539  CHECK_LOCATION();
2540 
2541  auto inputs = GetInputs(graph, layerIndex);
2542  CHECK_VALID_SIZE(inputs.size(), 1);
2543 
2544  auto outputs = GetOutputs(graph, layerIndex);
2545  CHECK_VALID_SIZE(outputs.size(), 1);
2546 
2547  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ReduceLayer();
2548  auto fbDescriptor = fbLayer->descriptor();
2549  auto flatBufferAxis = fbDescriptor->axis();
2550 
2551  armnn::ReduceDescriptor descriptor;
2552  descriptor.m_KeepDims = fbDescriptor->keepDims();
2553  descriptor.m_vAxis = std::vector<unsigned int>(flatBufferAxis->begin(), flatBufferAxis->end());
2554  descriptor.m_ReduceOperation = ToReduceOperation(fbDescriptor->reduceOperation());
2555 
2556  const std::string& layerName = GetLayerName(graph, layerIndex);
2557  IConnectableLayer* layer = m_Network->AddReduceLayer(descriptor, layerName.c_str());
2558 
2559  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2560  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2561 
2562  RegisterInputSlots(graph, layerIndex, layer);
2563  RegisterOutputSlots(graph, layerIndex, layer);
2564 }
2565 
2566 void IDeserializer::DeserializerImpl::ParseReshape(GraphPtr graph, unsigned int layerIndex)
2567 {
2568  CHECK_LAYERS(graph, 0, layerIndex);
2569  auto inputs = GetInputs(graph, layerIndex);
2570 
2571  auto outputs = GetOutputs(graph, layerIndex);
2572  CHECK_VALID_SIZE(outputs.size(), 1);
2573 
2574  armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2575  armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
2576 
2577  const auto targetDims = graph->layers()->Get(layerIndex)->layer_as_ReshapeLayer()->descriptor()->targetShape();
2578  std::vector<uint32_t> outputDims(targetDims->begin(), targetDims->begin() + targetDims->size());
2579 
2580  armnn::TensorInfo reshapeOutputTensorInfo = DeserializerImpl::OutputShapeOfReshape(inputTensorInfo, outputDims);
2581  const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
2582 
2583  const std::vector<uint32_t> expectedDims(outputs[0]->dimensions()->begin(),
2584  outputs[0]->dimensions()->begin() + outputs[0]->dimensions()->size());
2585 
2586  if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, expectedDims))
2587  {
2588  std::stringstream ss;
2589  ss << "New shape defined in reshape parameters "
2590  << reshapeOutputTensorShape
2591  << " does not equal output shape "
2592  << actualOutputTensorInfo.GetShape()
2593  << ": "
2594  << CHECK_LOCATION().AsString();
2595  throw ParseException(ss.str());
2596  }
2597 
2598  armnn::ReshapeDescriptor reshapeDesc;
2599  reshapeDesc.m_TargetShape = reshapeOutputTensorShape;
2600 
2601  auto layerName = GetLayerName(graph, layerIndex);
2602  IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
2603  layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
2604 
2605  RegisterInputSlots(graph, layerIndex, layer);
2606  RegisterOutputSlots(graph, layerIndex, layer);
2607 }
2608 
2609 void IDeserializer::DeserializerImpl::ParseResize(GraphPtr graph, unsigned int layerIndex)
2610 {
2611  CHECK_LAYERS(graph, 0, layerIndex);
2612 
2613  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2614  CHECK_VALID_SIZE(inputs.size(), 1);
2615 
2616  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2617  CHECK_VALID_SIZE(outputs.size(), 1);
2618 
2619  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_ResizeLayer()->descriptor();
2620 
2621  armnn::ResizeDescriptor descriptor;
2622  descriptor.m_TargetWidth = flatBufferDescriptor->targetWidth();
2623  descriptor.m_TargetHeight = flatBufferDescriptor->targetHeight();
2624  descriptor.m_Method = ToResizeMethod(flatBufferDescriptor->method());
2625  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2626  descriptor.m_AlignCorners = flatBufferDescriptor->alignCorners();
2627  descriptor.m_HalfPixelCenters = flatBufferDescriptor->halfPixelCenters();
2628 
2629  auto layerName = GetLayerName(graph, layerIndex);
2630  IConnectableLayer* layer = m_Network->AddResizeLayer(descriptor, layerName.c_str());
2631 
2632  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2633  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2634 
2635  RegisterInputSlots(graph, layerIndex, layer);
2636  RegisterOutputSlots(graph, layerIndex, layer);
2637 }
2638 
2639 
2640 /// @Note The ResizeBiliniar operation was deprecated and removed in favor of the Resize operation.
2641 /// This function is kept for backwards compatibility.
2642 void IDeserializer::DeserializerImpl::ParseResizeBilinear(GraphPtr graph, unsigned int layerIndex)
2643 {
2644  CHECK_LAYERS(graph, 0, layerIndex);
2645 
2646  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2647  CHECK_VALID_SIZE(inputs.size(), 1);
2648 
2649  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2650  CHECK_VALID_SIZE(outputs.size(), 1);
2651 
2652  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_ResizeBilinearLayer()->descriptor();
2653 
2654  armnn::ResizeDescriptor descriptor;
2655  descriptor.m_TargetWidth = flatBufferDescriptor->targetWidth();
2656  descriptor.m_TargetHeight = flatBufferDescriptor->targetHeight();
2658  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2659  descriptor.m_AlignCorners = flatBufferDescriptor->alignCorners();
2660  descriptor.m_HalfPixelCenters = flatBufferDescriptor->halfPixelCenters();
2661 
2662  auto layerName = GetLayerName(graph, layerIndex);
2663  IConnectableLayer* layer = m_Network->AddResizeLayer(descriptor, layerName.c_str());
2664 
2665  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2666  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2667 
2668  RegisterInputSlots(graph, layerIndex, layer);
2669  RegisterOutputSlots(graph, layerIndex, layer);
2670 }
2671 
2672 void IDeserializer::DeserializerImpl::ParseShape(GraphPtr graph, unsigned int layerIndex)
2673 {
2674  CHECK_LAYERS(graph, 0, layerIndex);
2675 
2676  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2677  CHECK_VALID_SIZE(inputs.size(), 1);
2678 
2679  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2680  CHECK_VALID_SIZE(outputs.size(), 1);
2681 
2682  auto layerName = GetLayerName(graph, layerIndex);
2683  IConnectableLayer* layer = m_Network->AddShapeLayer( layerName.c_str());
2684 
2685  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2686  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2687 
2688  RegisterInputSlots(graph, layerIndex, layer);
2689  RegisterOutputSlots(graph, layerIndex, layer);
2690 }
2691 
2692 void IDeserializer::DeserializerImpl::ParseSoftmax(GraphPtr graph, unsigned int layerIndex)
2693 {
2694  CHECK_LAYERS(graph, 0, layerIndex);
2695 
2696  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2697  CHECK_VALID_SIZE(inputs.size(), 1);
2698 
2699  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2700  CHECK_VALID_SIZE(outputs.size(), 1);
2701 
2702  armnn::SoftmaxDescriptor descriptor;
2703  descriptor.m_Beta = graph->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->descriptor()->beta();
2704  descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->descriptor()->axis();
2705  auto layerName = GetLayerName(graph, layerIndex);
2706 
2707  IConnectableLayer* layer = m_Network->AddSoftmaxLayer(descriptor, layerName.c_str());
2708 
2709  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2710  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2711 
2712  RegisterInputSlots(graph, layerIndex, layer);
2713  RegisterOutputSlots(graph, layerIndex, layer);
2714 }
2715 
2716 void IDeserializer::DeserializerImpl::ParseSpaceToBatchNd(GraphPtr graph, unsigned int layerIndex)
2717 {
2718  CHECK_LAYERS(graph, 0, layerIndex);
2719 
2720  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2721  CHECK_VALID_SIZE(inputs.size(), 1);
2722 
2723  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2724  CHECK_VALID_SIZE(outputs.size(), 1);
2725 
2726  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_SpaceToBatchNdLayer()->descriptor();
2727  auto flatBufferPadList = flatBufferDescriptor->padList();
2728  auto flatBufferBlockShape = flatBufferDescriptor->blockShape();
2729 
2730  if (flatBufferPadList->Length() % 2 != 0)
2731  {
2732  throw ParseException(fmt::format("The size of the pad list must be divisible by 2 {}",
2733  CHECK_LOCATION().AsString()));
2734  }
2735 
2736  std::vector<std::pair<unsigned int, unsigned int>> padList;
2737  padList.reserve(flatBufferPadList->Length() / 2);
2738  for (unsigned int i = 0; i < flatBufferPadList->Length() - 1; i += 2)
2739  {
2740  padList.emplace_back(flatBufferPadList->Get(i), flatBufferPadList->Get(i+1));
2741  }
2742 
2744  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2745  descriptor.m_BlockShape =
2746  std::vector<unsigned int>(flatBufferBlockShape->begin(), flatBufferBlockShape->end());
2747  descriptor.m_PadList = padList;
2748 
2749  auto layerName = GetLayerName(graph, layerIndex);
2750  IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(descriptor, layerName.c_str());
2751 
2752  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2753  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2754 
2755  RegisterInputSlots(graph, layerIndex, layer);
2756  RegisterOutputSlots(graph, layerIndex, layer);
2757 }
2758 
2759 void IDeserializer::DeserializerImpl::ParseSpaceToDepth(GraphPtr graph, unsigned int layerIndex)
2760 {
2761  CHECK_LAYERS(graph, 0, layerIndex);
2762 
2763  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2764  CHECK_VALID_SIZE(inputs.size(), 1);
2765 
2766  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2767  CHECK_VALID_SIZE(outputs.size(), 1);
2768 
2769  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_SpaceToDepthLayer()->descriptor();
2770 
2771  armnn::SpaceToDepthDescriptor descriptor;
2772  descriptor.m_BlockSize = flatBufferDescriptor->blockSize();
2773  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2774 
2775  auto layerName = GetLayerName(graph, layerIndex);
2776  IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str());
2777 
2778  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2779  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2780 
2781  RegisterInputSlots(graph, layerIndex, layer);
2782  RegisterOutputSlots(graph, layerIndex, layer);
2783 }
2784 
2786  NormalizationDescriptorPtr normalizationDescriptor,
2787  unsigned int layerIndex)
2788 {
2789  IgnoreUnused(layerIndex);
2791 
2792  switch (normalizationDescriptor->normChannelType())
2793  {
2795  {
2797  break;
2798  }
2800  {
2802  break;
2803  }
2804  default:
2805  {
2806  ARMNN_ASSERT_MSG(false, "Unsupported normalization channel type");
2807  }
2808  }
2809 
2810  switch (normalizationDescriptor->normMethodType())
2811  {
2813  {
2815  break;
2816  }
2818  {
2820  break;
2821  }
2822  default:
2823  {
2824  ARMNN_ASSERT_MSG(false, "Unsupported normalization method type");
2825  }
2826  }
2827 
2828  switch (normalizationDescriptor->dataLayout())
2829  {
2830  case DataLayout_NCHW:
2831  {
2833  break;
2834  }
2835  case DataLayout_NHWC:
2836  {
2838  break;
2839  }
2840  default:
2841  {
2842  ARMNN_ASSERT_MSG(false, "Unsupported data layout");
2843  }
2844  }
2845 
2846  desc.m_Alpha = normalizationDescriptor->alpha();
2847  desc.m_Beta = normalizationDescriptor->beta();
2848  desc.m_K = normalizationDescriptor->k();
2849  desc.m_NormSize = normalizationDescriptor->normSize();
2850 
2851  return desc;
2852 }
2853 
2854 void IDeserializer::DeserializerImpl::ParseNormalization(GraphPtr graph, unsigned int layerIndex)
2855 {
2856  CHECK_LAYERS(graph, 0, layerIndex);
2857 
2858  auto normalizationDes = graph->layers()->Get(layerIndex)->layer_as_NormalizationLayer()->descriptor();
2859 
2860  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2861  CHECK_VALID_SIZE(inputs.size(), 1);
2862 
2863  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2864  CHECK_VALID_SIZE(outputs.size(), 1);
2865 
2866  auto outputInfo = ToTensorInfo(outputs[0]);
2867 
2868  auto normalizationDescriptor = GetNormalizationDescriptor(normalizationDes, layerIndex);
2869  auto layerName = GetLayerName(graph, layerIndex);
2870 
2871  IConnectableLayer* layer = m_Network->AddNormalizationLayer(normalizationDescriptor, layerName.c_str());
2872  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2873 
2874  RegisterInputSlots(graph, layerIndex, layer);
2875  RegisterOutputSlots(graph, layerIndex, layer);
2876 }
2877 
2878 void IDeserializer::DeserializerImpl::ParseRsqrt(GraphPtr graph, unsigned int layerIndex)
2879 {
2880  CHECK_LAYERS(graph, 0, layerIndex);
2881  auto inputs = GetInputs(graph, layerIndex);
2882  CHECK_LOCATION();
2883  CHECK_VALID_SIZE(inputs.size(), 1);
2884 
2885  auto outputs = GetOutputs(graph, layerIndex);
2886  CHECK_VALID_SIZE(outputs.size(), 1);
2887 
2888  auto layerName = GetLayerName(graph, layerIndex);
2889 
2891  IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
2892  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2893  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2894 
2895  RegisterInputSlots(graph, layerIndex, layer);
2896  RegisterOutputSlots(graph, layerIndex, layer);
2897 }
2898 
2899 void IDeserializer::DeserializerImpl::ParseSlice(GraphPtr graph, unsigned int layerIndex)
2900 {
2901  CHECK_LAYERS(graph, 0, layerIndex);
2902 
2903  auto inputs = GetInputs(graph, layerIndex);
2904  CHECK_VALID_SIZE(inputs.size(), 1);
2905 
2906  auto outputs = GetOutputs(graph, layerIndex);
2907  CHECK_VALID_SIZE(outputs.size(), 1);
2908 
2909  auto fbDescriptor = graph->layers()->Get(layerIndex)->layer_as_SliceLayer()->descriptor();
2910 
2911  auto fbBegin = fbDescriptor->begin();
2912  auto fbSize = fbDescriptor->size();
2913 
2914  if (fbBegin->Length() != fbSize->Length())
2915  {
2916  throw ParseException(fmt::format("Begin and size descriptors must have the same length {}",
2917  CHECK_LOCATION().AsString()));
2918  }
2919 
2920  armnn::SliceDescriptor descriptor;
2921  descriptor.m_Begin.insert(descriptor.m_Begin.end(), fbBegin->begin(), fbBegin->end());
2922  descriptor.m_Size.insert(descriptor.m_Size.end(), fbSize->begin(), fbSize->end());
2923 
2924  auto layerName = GetLayerName(graph, layerIndex);
2925  IConnectableLayer* layer = m_Network->AddSliceLayer(descriptor, layerName.c_str());
2926 
2927  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2928  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2929 
2930  RegisterInputSlots(graph, layerIndex, layer);
2931  RegisterOutputSlots(graph, layerIndex, layer);
2932 }
2933 
2934 void IDeserializer::DeserializerImpl::ParseStridedSlice(GraphPtr graph, unsigned int layerIndex)
2935 {
2936  CHECK_LAYERS(graph, 0, layerIndex);
2937 
2938  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2939  CHECK_VALID_SIZE(inputs.size(), 1);
2940 
2941  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2942  CHECK_VALID_SIZE(outputs.size(), 1);
2943 
2944  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_StridedSliceLayer()->descriptor();
2945 
2946  auto flatBufferBegin = flatBufferDescriptor->begin();
2947  auto flatBufferEnd = flatBufferDescriptor->end();
2948  auto flatBufferStride = flatBufferDescriptor->stride();
2949 
2950  if (!(flatBufferBegin->Length() == flatBufferEnd->Length() &&
2951  flatBufferBegin->Length() == flatBufferStride->Length()))
2952  {
2953  throw ParseException(fmt::format("The size of the begin, end, and stride must be equal {}",
2954  CHECK_LOCATION().AsString()));
2955  }
2956 
2957  std::vector<int> begin(flatBufferBegin->begin(), flatBufferBegin->end());
2958  std::vector<int> end(flatBufferEnd->begin(), flatBufferEnd->end());
2959  std::vector<int> stride(flatBufferStride->begin(), flatBufferStride->end());
2960 
2961  armnn::StridedSliceDescriptor descriptor(begin, end, stride);
2962  descriptor.m_BeginMask = flatBufferDescriptor->beginMask();
2963  descriptor.m_EndMask = flatBufferDescriptor->endMask();
2964  descriptor.m_ShrinkAxisMask = flatBufferDescriptor->shrinkAxisMask();
2965  descriptor.m_EllipsisMask = flatBufferDescriptor->ellipsisMask();
2966  descriptor.m_NewAxisMask = flatBufferDescriptor->newAxisMask();
2967  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2968 
2969  auto layerName = GetLayerName(graph, layerIndex);
2970  IConnectableLayer* layer = m_Network->AddStridedSliceLayer(descriptor, layerName.c_str());
2971 
2972  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2973  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2974 
2975  RegisterInputSlots(graph, layerIndex, layer);
2976  RegisterOutputSlots(graph, layerIndex, layer);
2977 }
2978 
2979 void IDeserializer::DeserializerImpl::ParseSubtraction(GraphPtr graph, unsigned int layerIndex)
2980 {
2981  CHECK_LAYERS(graph, 0, layerIndex);
2982  auto inputs = GetInputs(graph, layerIndex);
2983  CHECK_LOCATION();
2984  CHECK_VALID_SIZE(inputs.size(), 2);
2985 
2986  auto outputs = GetOutputs(graph, layerIndex);
2987  CHECK_VALID_SIZE(outputs.size(), 1);
2988 
2989  auto layerName = GetLayerName(graph, layerIndex);
2990  IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str());
2991 
2992  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2993  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2994 
2995  RegisterInputSlots(graph, layerIndex, layer);
2996  RegisterOutputSlots(graph, layerIndex, layer);
2997 }
2998 
2999 void IDeserializer::DeserializerImpl::ParseGather(GraphPtr graph, unsigned int layerIndex)
3000 {
3001  CHECK_LAYERS(graph, 0, layerIndex);
3002 
3003  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
3004  CHECK_VALID_SIZE(inputs.size(), 2);
3005 
3006  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
3007  CHECK_VALID_SIZE(outputs.size(), 1);
3008 
3009  armnn::GatherDescriptor descriptor;
3010  descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_GatherLayer()->descriptor()->axis();
3011 
3012  auto layerName = GetLayerName(graph, layerIndex);
3013  IConnectableLayer* layer = m_Network->AddGatherLayer(descriptor, layerName.c_str());
3014 
3015  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3016  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3017 
3018  RegisterInputSlots(graph, layerIndex, layer);
3019  RegisterOutputSlots(graph, layerIndex, layer);
3020 }
3021 
3022 void IDeserializer::DeserializerImpl::ParseGatherNd(GraphPtr graph, unsigned int layerIndex)
3023 {
3024  CHECK_LAYERS(graph, 0, layerIndex);
3025 
3026  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
3027  CHECK_VALID_SIZE(inputs.size(), 2);
3028 
3029  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
3030  CHECK_VALID_SIZE(outputs.size(), 1);
3031 
3032  auto layerName = GetLayerName(graph, layerIndex);
3033  IConnectableLayer* layer = m_Network->AddGatherNdLayer(layerName.c_str());
3034 
3035  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3036  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3037 
3038  RegisterInputSlots(graph, layerIndex, layer);
3039  RegisterOutputSlots(graph, layerIndex, layer);
3040 }
3041 
3042 void IDeserializer::DeserializerImpl::ParseMean(GraphPtr graph, unsigned int layerIndex)
3043 {
3044  CHECK_LAYERS(graph, 0, layerIndex);
3045 
3046  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
3047  CHECK_VALID_SIZE(inputs.size(), 1);
3048 
3049  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
3050  CHECK_VALID_SIZE(outputs.size(), 1);
3051 
3052  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_MeanLayer()->descriptor();
3053  auto flatBufferAxis = flatBufferDescriptor->axis();
3054  auto flatBufferKeepDims = flatBufferDescriptor->keepDims();
3055 
3056  armnn::MeanDescriptor descriptor;
3057  descriptor.m_Axis = std::vector<unsigned int>(flatBufferAxis->begin(), flatBufferAxis->end());
3058  descriptor.m_KeepDims = flatBufferKeepDims;
3059 
3060  auto layerName = GetLayerName(graph, layerIndex);
3061  IConnectableLayer* layer = m_Network->AddMeanLayer(descriptor, layerName.c_str());
3062 
3063  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3064  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3065 
3066  RegisterInputSlots(graph, layerIndex, layer);
3067  RegisterOutputSlots(graph, layerIndex, layer);
3068 }
3069 
3070 void IDeserializer::DeserializerImpl::ParseSplitter(GraphPtr graph, unsigned int layerIndex)
3071 {
3072  CHECK_LAYERS(graph, 0, layerIndex);
3073 
3074  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
3075  CHECK_VALID_SIZE(inputs.size(), 1);
3076 
3077  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
3078 
3079  auto flatBufferViewsDescriptor = graph->layers()->Get(layerIndex)->layer_as_SplitterLayer()->descriptor();
3080  auto flatBufferViewSizes = flatBufferViewsDescriptor->viewSizes();
3081  auto flatBufferOriginsDescriptor = flatBufferViewsDescriptor->origins();
3082  auto flatBufferViewOrigins = flatBufferOriginsDescriptor->viewOrigins();
3083  uint32_t numViews = flatBufferOriginsDescriptor->numViews();
3084  uint32_t numDimensions = flatBufferOriginsDescriptor->numDimensions();
3085 
3086  // Check numViews and numDimensions corresponds to the ones already serialized ...
3087  // numViews == flatBufferViewSizes.size();
3088  // foreach: numDimensions == flatBufferViewSizes[x].size();
3089 
3090  armnn::ViewsDescriptor viewsDescriptor(numViews, numDimensions);
3091  for(unsigned int vIdx = 0; vIdx < numViews; ++vIdx)
3092  {
3093  for (unsigned int dIdx = 0; dIdx < numDimensions; ++dIdx)
3094  {
3095  viewsDescriptor.SetViewSize(vIdx, dIdx, flatBufferViewSizes->Get(vIdx)->data()->Get(dIdx));
3096  viewsDescriptor.SetViewOriginCoord(vIdx, dIdx, flatBufferViewOrigins->Get(vIdx)->data()->Get(dIdx));
3097  }
3098  }
3099 
3100  auto layerName = GetLayerName(graph, layerIndex);
3101  IConnectableLayer* layer = m_Network->AddSplitterLayer(viewsDescriptor, layerName.c_str());
3102 
3103  // I could have as many outputs as views ...
3104  for(unsigned int vIdx = 0; vIdx < numViews; ++vIdx)
3105  {
3106  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[vIdx]);
3107  layer->GetOutputSlot(vIdx).SetTensorInfo(outputTensorInfo);
3108  }
3109 
3110  RegisterInputSlots(graph, layerIndex, layer);
3111  RegisterOutputSlots(graph, layerIndex, layer);
3112 }
3113 
3115 {
3116  armnn::LstmDescriptor desc;
3117 
3118  desc.m_ActivationFunc = lstmDescriptor->activationFunc();
3119  desc.m_ClippingThresCell = lstmDescriptor->clippingThresCell();
3120  desc.m_ClippingThresProj = lstmDescriptor->clippingThresProj();
3121  desc.m_CifgEnabled = lstmDescriptor->cifgEnabled();
3122  desc.m_PeepholeEnabled = lstmDescriptor->peepholeEnabled();
3123  desc.m_ProjectionEnabled = lstmDescriptor->projectionEnabled();
3124  desc.m_LayerNormEnabled = lstmDescriptor->layerNormEnabled();
3125 
3126  return desc;
3127 }
3128 
3129 void IDeserializer::DeserializerImpl::ParseLstm(GraphPtr graph, unsigned int layerIndex)
3130 {
3131  CHECK_LAYERS(graph, 0, layerIndex);
3132 
3133  auto inputs = GetInputs(graph, layerIndex);
3134  CHECK_VALID_SIZE(inputs.size(), 3);
3135 
3136  auto outputs = GetOutputs(graph, layerIndex);
3137  CHECK_VALID_SIZE(outputs.size(), 4);
3138 
3139  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_LstmLayer();
3140  auto layerName = GetLayerName(graph, layerIndex);
3141  auto flatBufferDescriptor = flatBufferLayer->descriptor();
3142  auto flatBufferInputParams = flatBufferLayer->inputParams();
3143 
3144  auto lstmDescriptor = GetLstmDescriptor(flatBufferDescriptor);
3145 
3146  armnn::LstmInputParams lstmInputParams;
3147 
3148  armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights());
3149  armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights());
3150  armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights());
3151  armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights());
3152  armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights());
3153  armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights());
3154  armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias());
3155  armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias());
3156  armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias());
3157 
3158  lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights;
3159  lstmInputParams.m_InputToCellWeights = &inputToCellWeights;
3160  lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights;
3161  lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3162  lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights;
3163  lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3164  lstmInputParams.m_ForgetGateBias = &forgetGateBias;
3165  lstmInputParams.m_CellBias = &cellBias;
3166  lstmInputParams.m_OutputGateBias = &outputGateBias;
3167 
3168  armnn::ConstTensor inputToInputWeights;
3169  armnn::ConstTensor recurrentToInputWeights;
3170  armnn::ConstTensor cellToInputWeights;
3171  armnn::ConstTensor inputGateBias;
3172  if (!lstmDescriptor.m_CifgEnabled)
3173  {
3174  inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights());
3175  recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights());
3176  cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights());
3177  inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias());
3178 
3179  lstmInputParams.m_InputToInputWeights = &inputToInputWeights;
3180  lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights;
3181  lstmInputParams.m_CellToInputWeights = &cellToInputWeights;
3182  lstmInputParams.m_InputGateBias = &inputGateBias;
3183  }
3184 
3185  armnn::ConstTensor projectionWeights;
3186  armnn::ConstTensor projectionBias;
3187  if (lstmDescriptor.m_ProjectionEnabled)
3188  {
3189  projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights());
3190  projectionBias = ToConstTensor(flatBufferInputParams->projectionBias());
3191 
3192  lstmInputParams.m_ProjectionWeights = &projectionWeights;
3193  lstmInputParams.m_ProjectionBias = &projectionBias;
3194  }
3195 
3196  armnn::ConstTensor cellToForgetWeights;
3197  armnn::ConstTensor cellToOutputWeights;
3198  if (lstmDescriptor.m_PeepholeEnabled)
3199  {
3200  cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights());
3201  cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights());
3202 
3203  lstmInputParams.m_CellToForgetWeights = &cellToForgetWeights;
3204  lstmInputParams.m_CellToOutputWeights = &cellToOutputWeights;
3205  }
3206 
3207  armnn::ConstTensor inputLayerNormWeights;
3208  armnn::ConstTensor forgetLayerNormWeights;
3209  armnn::ConstTensor cellLayerNormWeights;
3210  armnn::ConstTensor outputLayerNormWeights;
3211  if (lstmDescriptor.m_LayerNormEnabled)
3212  {
3213  if (!lstmDescriptor.m_CifgEnabled)
3214  {
3215  inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights());
3216  lstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights;
3217  }
3218  forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights());
3219  cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights());
3220  outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights());
3221 
3222  lstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3223  lstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights;
3224  lstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights;
3225  }
3226 
3227  IConnectableLayer* layer = m_Network->AddLstmLayer(lstmDescriptor, lstmInputParams, layerName.c_str());
3228 
3229  armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[0]);
3230  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo1);
3231 
3232  armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[1]);
3233  layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo2);
3234 
3235  armnn::TensorInfo outputTensorInfo3 = ToTensorInfo(outputs[2]);
3236  layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo3);
3237 
3238  armnn::TensorInfo outputTensorInfo4 = ToTensorInfo(outputs[3]);
3239  layer->GetOutputSlot(3).SetTensorInfo(outputTensorInfo4);
3240 
3241  RegisterInputSlots(graph, layerIndex, layer);
3242  RegisterOutputSlots(graph, layerIndex, layer);
3243 }
3244 
3246 {
3248 
3249  desc.m_CifgEnabled = qLstmDescriptor->cifgEnabled();
3250  desc.m_PeepholeEnabled = qLstmDescriptor->peepholeEnabled();
3251  desc.m_ProjectionEnabled = qLstmDescriptor->projectionEnabled();
3252  desc.m_LayerNormEnabled = qLstmDescriptor->layerNormEnabled();
3253 
3254  desc.m_CellClip = qLstmDescriptor->cellClip();
3255  desc.m_ProjectionClip = qLstmDescriptor->projectionClip();
3256 
3257  desc.m_InputIntermediateScale = qLstmDescriptor->inputIntermediateScale();
3258  desc.m_ForgetIntermediateScale = qLstmDescriptor->forgetIntermediateScale();
3259  desc.m_CellIntermediateScale = qLstmDescriptor->cellIntermediateScale();
3260  desc.m_OutputIntermediateScale = qLstmDescriptor->outputIntermediateScale();
3261 
3262  desc.m_HiddenStateScale = qLstmDescriptor->hiddenStateScale();
3263  desc.m_HiddenStateZeroPoint = qLstmDescriptor->hiddenStateZeroPoint();
3264 
3265  return desc;
3266 }
3267 
3268 void IDeserializer::DeserializerImpl::ParseQLstm(GraphPtr graph, unsigned int layerIndex)
3269 {
3270  CHECK_LAYERS(graph, 0, layerIndex);
3271 
3272  auto inputs = GetInputs(graph, layerIndex);
3273  CHECK_VALID_SIZE(inputs.size(), 3);
3274 
3275  auto outputs = GetOutputs(graph, layerIndex);
3276  CHECK_VALID_SIZE(outputs.size(), 3);
3277 
3278  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_QLstmLayer();
3279  auto layerName = GetLayerName(graph, layerIndex);
3280  auto flatBufferDescriptor = flatBufferLayer->descriptor();
3281  auto flatBufferInputParams = flatBufferLayer->inputParams();
3282 
3283  auto qLstmDescriptor = GetQLstmDescriptor(flatBufferDescriptor);
3284  armnn::LstmInputParams qLstmInputParams;
3285 
3286  // Mandatory params
3287  armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights());
3288  armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights());
3289  armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights());
3290  armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights());
3291  armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights());
3292  armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights());
3293  armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias());
3294  armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias());
3295  armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias());
3296 
3297  qLstmInputParams.m_InputToForgetWeights = &inputToForgetWeights;
3298  qLstmInputParams.m_InputToCellWeights = &inputToCellWeights;
3299  qLstmInputParams.m_InputToOutputWeights = &inputToOutputWeights;
3300  qLstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3301  qLstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights;
3302  qLstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3303  qLstmInputParams.m_ForgetGateBias = &forgetGateBias;
3304  qLstmInputParams.m_CellBias = &cellBias;
3305  qLstmInputParams.m_OutputGateBias = &outputGateBias;
3306 
3307  // Optional CIFG params
3308  armnn::ConstTensor inputToInputWeights;
3309  armnn::ConstTensor recurrentToInputWeights;
3310  armnn::ConstTensor inputGateBias;
3311 
3312  if (!qLstmDescriptor.m_CifgEnabled)
3313  {
3314  inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights());
3315  recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights());
3316  inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias());
3317 
3318  qLstmInputParams.m_InputToInputWeights = &inputToInputWeights;
3319  qLstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights;
3320  qLstmInputParams.m_InputGateBias = &inputGateBias;
3321  }
3322 
3323  // Optional projection params
3324  armnn::ConstTensor projectionWeights;
3325  armnn::ConstTensor projectionBias;
3326 
3327  if (qLstmDescriptor.m_ProjectionEnabled)
3328  {
3329  projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights());
3330  projectionBias = ToConstTensor(flatBufferInputParams->projectionBias());
3331 
3332  qLstmInputParams.m_ProjectionWeights = &projectionWeights;
3333  qLstmInputParams.m_ProjectionBias = &projectionBias;
3334  }
3335 
3336  // Optional peephole params
3337  armnn::ConstTensor cellToInputWeights;
3338  armnn::ConstTensor cellToForgetWeights;
3339  armnn::ConstTensor cellToOutputWeights;
3340 
3341  if (qLstmDescriptor.m_PeepholeEnabled)
3342  {
3343  if (!qLstmDescriptor.m_CifgEnabled)
3344  {
3345  cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights());
3346  qLstmInputParams.m_CellToInputWeights = &cellToInputWeights;
3347  }
3348 
3349  cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights());
3350  cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights());
3351 
3352  qLstmInputParams.m_CellToForgetWeights = &cellToForgetWeights;
3353  qLstmInputParams.m_CellToOutputWeights = &cellToOutputWeights;
3354  }
3355 
3356  // Optional layer norm params
3357  armnn::ConstTensor inputLayerNormWeights;
3358  armnn::ConstTensor forgetLayerNormWeights;
3359  armnn::ConstTensor cellLayerNormWeights;
3360  armnn::ConstTensor outputLayerNormWeights;
3361 
3362  if (qLstmDescriptor.m_LayerNormEnabled)
3363  {
3364  if (!qLstmDescriptor.m_CifgEnabled)
3365  {
3366  inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights());
3367  qLstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights;
3368  }
3369 
3370  forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights());
3371  cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights());
3372  outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights());
3373 
3374  qLstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3375  qLstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights;
3376  qLstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights;
3377  }
3378 
3379  IConnectableLayer* layer = m_Network->AddQLstmLayer(qLstmDescriptor, qLstmInputParams, layerName.c_str());
3380 
3381  armnn::TensorInfo outputStateOutInfo = ToTensorInfo(outputs[0]);
3382  layer->GetOutputSlot(0).SetTensorInfo(outputStateOutInfo);
3383 
3384  armnn::TensorInfo cellStateOutInfo = ToTensorInfo(outputs[1]);
3385  layer->GetOutputSlot(1).SetTensorInfo(cellStateOutInfo);
3386 
3387  armnn::TensorInfo outputInfo = ToTensorInfo(outputs[2]);
3388  layer->GetOutputSlot(2).SetTensorInfo(outputInfo);
3389 
3390  RegisterInputSlots(graph, layerIndex, layer);
3391  RegisterOutputSlots(graph, layerIndex, layer);
3392 }
3393 
3394 void IDeserializer::DeserializerImpl::ParseQuantizedLstm(GraphPtr graph, unsigned int layerIndex)
3395 {
3396  CHECK_LAYERS(graph, 0, layerIndex);
3397 
3398  auto inputs = GetInputs(graph, layerIndex);
3399  CHECK_VALID_SIZE(inputs.size(), 3);
3400 
3401  auto outputs = GetOutputs(graph, layerIndex);
3402  CHECK_VALID_SIZE(outputs.size(), 2);
3403 
3404  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_QuantizedLstmLayer();
3405  auto layerName = GetLayerName(graph, layerIndex);
3406  auto flatBufferInputParams = flatBufferLayer->inputParams();
3407 
3408  armnn::QuantizedLstmInputParams lstmInputParams;
3409 
3410  armnn::ConstTensor inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights());
3411  armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights());
3412  armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights());
3413  armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights());
3414  armnn::ConstTensor recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights());
3415  armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights());
3416  armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights());
3417  armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights());
3418  armnn::ConstTensor inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias());
3419  armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias());
3420  armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias());
3421  armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias());
3422 
3423  lstmInputParams.m_InputToInputWeights = &inputToInputWeights;
3424  lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights;
3425  lstmInputParams.m_InputToCellWeights = &inputToCellWeights;
3426  lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights;
3427  lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights;
3428  lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3429  lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights;
3430  lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3431  lstmInputParams.m_InputGateBias = &inputGateBias;
3432  lstmInputParams.m_ForgetGateBias = &forgetGateBias;
3433  lstmInputParams.m_CellBias = &cellBias;
3434  lstmInputParams.m_OutputGateBias = &outputGateBias;
3435 
3436  IConnectableLayer* layer = m_Network->AddQuantizedLstmLayer(lstmInputParams, layerName.c_str());
3437 
3438  armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[0]);
3439  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo1);
3440 
3441  armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[1]);
3442  layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo2);
3443 
3444  RegisterInputSlots(graph, layerIndex, layer);
3445  RegisterOutputSlots(graph, layerIndex, layer);
3446 }
3447 
3448 void IDeserializer::DeserializerImpl::ParseDequantize(GraphPtr graph, unsigned int layerIndex)
3449 {
3450  CHECK_LAYERS(graph, 0, layerIndex);
3451 
3452  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
3453  CHECK_VALID_SIZE(inputs.size(), 1);
3454 
3455  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
3456  CHECK_VALID_SIZE(outputs.size(), 1);
3457 
3458  const std::string layerName = GetLayerName(graph, layerIndex);
3459  IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
3460 
3461  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3462  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3463 
3464  RegisterInputSlots(graph, layerIndex, layer);
3465  RegisterOutputSlots(graph, layerIndex, layer);
3466 }
3467 
3468 void IDeserializer::DeserializerImpl::ParseMerge(GraphPtr graph, unsigned int layerIndex)
3469 {
3470  CHECK_LAYERS(graph, 0, layerIndex);
3471 
3472  TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
3473  CHECK_VALID_SIZE(inputs.size(), 2);
3474 
3475  TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
3476  CHECK_VALID_SIZE(outputs.size(), 1);
3477 
3478  const std::string layerName = GetLayerName(graph, layerIndex);
3479  IConnectableLayer* layer = m_Network->AddMergeLayer(layerName.c_str());
3480 
3481  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3482  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3483 
3484  RegisterInputSlots(graph, layerIndex, layer);
3485  RegisterOutputSlots(graph, layerIndex, layer);
3486 }
3487 
3488 void IDeserializer::DeserializerImpl::ParseSwitch(GraphPtr graph, unsigned int layerIndex)
3489 {
3490  CHECK_LAYERS(graph, 0, layerIndex);
3491  auto inputs = GetInputs(graph, layerIndex);
3492  CHECK_LOCATION();
3493  CHECK_VALID_SIZE(inputs.size(), 2);
3494 
3495  auto outputs = GetOutputs(graph, layerIndex);
3496  CHECK_VALID_SIZE(outputs.size(), 2);
3497 
3498  auto layerName = GetLayerName(graph, layerIndex);
3499  IConnectableLayer* layer = m_Network->AddSwitchLayer(layerName.c_str());
3500 
3501  armnn::TensorInfo output0TensorInfo = ToTensorInfo(outputs[0]);
3502  layer->GetOutputSlot(0).SetTensorInfo(output0TensorInfo);
3503 
3504  armnn::TensorInfo output1TensorInfo = ToTensorInfo(outputs[1]);
3505  layer->GetOutputSlot(1).SetTensorInfo(output1TensorInfo);
3506 
3507  RegisterInputSlots(graph, layerIndex, layer);
3508  RegisterOutputSlots(graph, layerIndex, layer);
3509 }
3510 
3511 void IDeserializer::DeserializerImpl::ParsePrelu(GraphPtr graph, unsigned int layerIndex)
3512 {
3513  CHECK_LAYERS(graph, 0, layerIndex);
3514  auto inputs = GetInputs(graph, layerIndex);
3515  CHECK_LOCATION();
3516  CHECK_VALID_SIZE(inputs.size(), 2);
3517 
3518  auto outputs = GetOutputs(graph, layerIndex);
3519  CHECK_VALID_SIZE(outputs.size(), 1);
3520 
3521  auto layerName = GetLayerName(graph, layerIndex);
3522  IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
3523 
3524  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3525  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3526 
3527  RegisterInputSlots(graph, layerIndex, layer);
3528  RegisterOutputSlots(graph, layerIndex, layer);
3529 }
3530 
3531 void IDeserializer::DeserializerImpl::ParseTranspose(GraphPtr graph, unsigned int layerIndex)
3532 {
3533  CHECK_LAYERS(graph, 0, layerIndex);
3534 
3535  auto dimsMapping = graph->layers()->Get(layerIndex)->layer_as_TransposeLayer()->descriptor()->dimMappings();
3536 
3537  auto inputs = GetInputs(graph, layerIndex);
3538  CHECK_VALID_SIZE(inputs.size(), 1);
3539 
3540  auto outputs = GetOutputs(graph, layerIndex);
3541  CHECK_VALID_SIZE(outputs.size(), 1);
3542  auto outputInfo = ToTensorInfo(outputs[0]);
3543 
3544  auto layerName = GetLayerName(graph, layerIndex);
3545  const armnn::TransposeDescriptor descriptor(armnn::PermutationVector(dimsMapping->data(), dimsMapping->Length()));
3546 
3547  IConnectableLayer* layer = m_Network->AddTransposeLayer(descriptor, layerName.c_str());
3548  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
3549 
3550  RegisterInputSlots(graph, layerIndex, layer);
3551  RegisterOutputSlots(graph, layerIndex, layer);
3552 }
3553 
3554 void IDeserializer::DeserializerImpl::ParseTransposeConvolution2d(GraphPtr graph, unsigned int layerIndex)
3555 {
3556  CHECK_LAYERS(graph, 0, layerIndex);
3557 
3558  auto inputs = GetInputs(graph, layerIndex);
3559  CHECK_VALID_SIZE(inputs.size(), 1);
3560 
3561  auto outputs = GetOutputs(graph, layerIndex);
3562  CHECK_VALID_SIZE(outputs.size(), 1);
3563 
3564  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_TransposeConvolution2dLayer();
3565  auto layerName = GetLayerName(graph, layerIndex);
3566  auto serializerDescriptor = serializerLayer->descriptor();
3567 
3569  descriptor.m_PadLeft = serializerDescriptor->padLeft();
3570  descriptor.m_PadRight = serializerDescriptor->padRight();
3571  descriptor.m_PadTop = serializerDescriptor->padTop();
3572  descriptor.m_PadBottom = serializerDescriptor->padBottom();
3573  descriptor.m_StrideX = serializerDescriptor->strideX();
3574  descriptor.m_StrideY = serializerDescriptor->strideY();;
3575  descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();;
3576  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
3577 
3578  // weights & biases
3579  armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights());
3580  armnn::Optional<armnn::ConstTensor> optionalBiases;
3581  if (descriptor.m_BiasEnabled)
3582  {
3583  armnn::ConstTensor biases = ToConstTensor(serializerLayer->biases());
3584  optionalBiases = armnn::MakeOptional<armnn::ConstTensor>(biases);
3585  }
3586 
3587  IConnectableLayer* layer = m_Network->AddTransposeConvolution2dLayer(descriptor,
3588  weights,
3589  optionalBiases,
3590  layerName.c_str());
3591 
3592  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3593  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3594 
3595  RegisterInputSlots(graph, layerIndex, layer);
3596  RegisterOutputSlots(graph, layerIndex, layer);
3597 }
3598 
3599 void IDeserializer::DeserializerImpl::ParseStack(GraphPtr graph, unsigned int layerIndex)
3600 {
3601  CHECK_LAYERS(graph, 0, layerIndex);
3602  auto inputs = GetInputs(graph, layerIndex);
3603 
3604  auto outputs = GetOutputs(graph, layerIndex);
3605  CHECK_VALID_SIZE(outputs.size(), 1);
3606 
3607  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_StackLayer()->descriptor();
3608  unsigned int axis = flatBufferDescriptor->axis();
3609  unsigned int numInputs = flatBufferDescriptor->numInputs();
3610  CHECK_VALID_SIZE(inputs.size(), numInputs);
3611 
3612  auto flatBufferInputShape = flatBufferDescriptor->inputShape();
3613  std::vector<uint32_t> vectorInputShape(flatBufferInputShape->begin(),
3614  flatBufferInputShape->begin() + flatBufferInputShape->size());
3615 
3616  TensorShape inputShape(static_cast<unsigned int>(vectorInputShape.size()), vectorInputShape.data());
3617  armnn::StackDescriptor descriptor(axis, numInputs, inputShape);
3618 
3619  for (unsigned int i=0; i<inputs.size(); ++i)
3620  {
3621  armnn::TensorShape inputShape = ToTensorInfo(inputs[i]).GetShape();
3622  if (descriptor.m_InputShape != inputShape)
3623  {
3624  std::stringstream ss;
3625  ss << "Shape of input "
3626  << i
3627  << " "
3628  << inputShape
3629  << " does not equal defined input shape "
3630  << descriptor.m_InputShape
3631  << ": "
3632  << CHECK_LOCATION().AsString();
3633  throw ParseException(ss.str());
3634  }
3635  }
3636 
3637  auto layerName = GetLayerName(graph, layerIndex);
3638  IConnectableLayer* layer = m_Network->AddStackLayer(descriptor, layerName.c_str());
3639 
3640  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3641  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3642 
3643  RegisterInputSlots(graph, layerIndex, layer);
3644  RegisterOutputSlots(graph, layerIndex, layer);
3645 }
3646 
3647 void IDeserializer::DeserializerImpl::ParseStandIn(GraphPtr graph, unsigned int layerIndex)
3648 {
3649  CHECK_LAYERS(graph, 0, layerIndex);
3650 
3651  auto inputs = GetInputs(graph, layerIndex);
3652  auto outputs = GetOutputs(graph, layerIndex);
3653 
3654  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_StandInLayer();
3655  auto fbDescriptor = fbLayer->descriptor();
3656 
3657  armnn::StandInDescriptor descriptor;
3658  descriptor.m_NumInputs = fbDescriptor->numInputs();
3659  descriptor.m_NumOutputs = fbDescriptor->numOutputs();
3660 
3661  CHECK_VALID_SIZE(inputs.size(), descriptor.m_NumInputs);
3662  CHECK_VALID_SIZE(outputs.size(), descriptor.m_NumOutputs);
3663 
3664  const std::string layerName = GetLayerName(graph, layerIndex);
3665  armnn::IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
3666 
3667  for (unsigned int i = 0u; i < descriptor.m_NumOutputs; ++i)
3668  {
3669  armnn::TensorInfo outputInfo = ToTensorInfo(outputs[i]);
3670  layer->GetOutputSlot(i).SetTensorInfo(outputInfo);
3671  }
3672 
3673  RegisterInputSlots(graph, layerIndex, layer);
3674  RegisterOutputSlots(graph, layerIndex, layer);
3675 }
3676 
3679 {
3681 
3682  desc.m_ActivationFunc = descriptor->activationFunc();
3683  desc.m_ClippingThresCell = descriptor->clippingThresCell();
3684  desc.m_ClippingThresProj = descriptor->clippingThresProj();
3685  desc.m_CifgEnabled = descriptor->cifgEnabled();
3686  desc.m_PeepholeEnabled = descriptor->peepholeEnabled();
3687  desc.m_ProjectionEnabled = descriptor->projectionEnabled();
3688  desc.m_LayerNormEnabled = descriptor->layerNormEnabled();
3689  desc.m_TimeMajor = descriptor->timeMajor();
3690 
3691  return desc;
3692 }
3693 
3694 void IDeserializer::DeserializerImpl::ParseUnidirectionalSequenceLstm(GraphPtr graph, unsigned int layerIndex)
3695 {
3696  CHECK_LAYERS(graph, 0, layerIndex);
3697 
3698  auto inputs = GetInputs(graph, layerIndex);
3699  CHECK_VALID_SIZE(inputs.size(), 3);
3700 
3701  auto outputs = GetOutputs(graph, layerIndex);
3702  CHECK_VALID_SIZE(outputs.size(), 3);
3703 
3704  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_UnidirectionalSequenceLstmLayer();
3705  auto layerName = GetLayerName(graph, layerIndex);
3706  auto flatBufferDescriptor = flatBufferLayer->descriptor();
3707  auto flatBufferInputParams = flatBufferLayer->inputParams();
3708 
3709  auto descriptor = GetUnidirectionalSequenceLstmDescriptor(flatBufferDescriptor);
3710 
3711  armnn::LstmInputParams lstmInputParams;
3712 
3713  armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights());
3714  armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights());
3715  armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights());
3716  armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights());
3717  armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights());
3718  armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights());
3719  armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias());
3720  armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias());
3721  armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias());
3722 
3723  lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights;
3724  lstmInputParams.m_InputToCellWeights = &inputToCellWeights;
3725  lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights;
3726  lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3727  lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights;
3728  lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3729  lstmInputParams.m_ForgetGateBias = &forgetGateBias;
3730  lstmInputParams.m_CellBias = &cellBias;
3731  lstmInputParams.m_OutputGateBias = &outputGateBias;
3732 
3733  armnn::ConstTensor inputToInputWeights;
3734  armnn::ConstTensor recurrentToInputWeights;
3735  armnn::ConstTensor cellToInputWeights;
3736  armnn::ConstTensor inputGateBias;
3737  if (!descriptor.m_CifgEnabled)
3738  {
3739  inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights());
3740  recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights());
3741  inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias());
3742 
3743  lstmInputParams.m_InputToInputWeights = &inputToInputWeights;
3744  lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights;
3745  lstmInputParams.m_InputGateBias = &inputGateBias;
3746 
3747  if (descriptor.m_PeepholeEnabled)
3748  {
3749  cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights());
3750  lstmInputParams.m_CellToInputWeights = &cellToInputWeights;
3751  }
3752  }
3753 
3754  armnn::ConstTensor projectionWeights;
3755  armnn::ConstTensor projectionBias;
3756  if (descriptor.m_ProjectionEnabled)
3757  {
3758  projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights());
3759  projectionBias = ToConstTensor(flatBufferInputParams->projectionBias());
3760 
3761  lstmInputParams.m_ProjectionWeights = &projectionWeights;
3762  lstmInputParams.m_ProjectionBias = &projectionBias;
3763  }
3764 
3765  armnn::ConstTensor cellToForgetWeights;
3766  armnn::ConstTensor cellToOutputWeights;
3767  if (descriptor.m_PeepholeEnabled)
3768  {
3769  cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights());
3770  cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights());
3771 
3772  lstmInputParams.m_CellToForgetWeights = &cellToForgetWeights;
3773  lstmInputParams.m_CellToOutputWeights = &cellToOutputWeights;
3774  }
3775 
3776  armnn::ConstTensor inputLayerNormWeights;
3777  armnn::ConstTensor forgetLayerNormWeights;
3778  armnn::ConstTensor cellLayerNormWeights;
3779  armnn::ConstTensor outputLayerNormWeights;
3780  if (descriptor.m_LayerNormEnabled)
3781  {
3782  if (!descriptor.m_CifgEnabled)
3783  {
3784  inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights());
3785  lstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights;
3786  }
3787  forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights());
3788  cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights());
3789  outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights());
3790 
3791  lstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3792  lstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights;
3793  lstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights;
3794  }
3795 
3796  IConnectableLayer* layer = m_Network->AddUnidirectionalSequenceLstmLayer(descriptor,
3797  lstmInputParams,
3798  layerName.c_str());
3799 
3800  armnn::TensorInfo outputTensorInfo0 = ToTensorInfo(outputs[0]);
3801  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo0);
3802 
3803  armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[1]);
3804  layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo1);
3805 
3806  armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[2]);
3807  layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo2);
3808 
3809  RegisterInputSlots(graph, layerIndex, layer);
3810  RegisterOutputSlots(graph, layerIndex, layer);
3811 }
3812 
3813 } // namespace armnnDeserializer
static armnn::NormalizationDescriptor GetNormalizationDescriptor(NormalizationDescriptorPtr normalizationDescriptor, unsigned int layerIndex)
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).
float m_Eps
Used to avoid dividing by zero.
virtual unsigned int GetNumOutputSlots() const =0
Returns the number of connectable output slots.
armnn::LogicalBinaryOperation ToLogicalBinaryOperation(armnnSerializer::LogicalBinaryOperation operation)
bool m_ProjectionEnabled
Enable/disable the projection layer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
const ConstTensor * m_ProjectionWeights
Definition: LstmParams.hpp:55
UnaryOperation m_Operation
Specifies the elementwiseUnary operation to execute.
static TensorRawPtrVector GetOutputs(const GraphPtr &graph, unsigned int layerIndex)
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:66
float m_ScaleW
Center size encoding scale weight.
#define CHECK_LAYERS(GRAPH, LAYERS_INDEX, LAYER_INDEX)
const ConstTensor * m_CellBias
Definition: LstmParams.hpp:53
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
armnn::ReduceOperation ToReduceOperation(armnnSerializer::ReduceOperation operation)
virtual unsigned int GetNumInputSlots() const =0
Returns the number of connectable input slots.
DataLayout
Definition: Types.hpp:62
float m_K
Kappa value used for the across channel normalization equation.
A TransposeConvolution2dDescriptor for the TransposeConvolution2dLayer.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
const TensorShape & GetShape() const
Definition: Tensor.hpp:191
uint32_t m_PoolWidth
Pooling width value.
const ConstTensor * m_RecurrentToOutputWeights
uint32_t m_PadBottom
Padding bottom value in the height dimension.
uint32_t m_PadLeft
Padding left value in the width dimension.
float m_ClippingThresProj
Clipping threshold value for the projection.
uint32_t m_PoolDepth
Pooling depth value.
std::string AsString() const
Definition: Exceptions.hpp:29
static LayerBaseRawPtr GetBaseLayer(const GraphPtr &graphPtr, unsigned int layerIndex)
A ReshapeDescriptor for the ReshapeLayer.
const armnnSerializer::ConstTensor * ConstTensorRawPtr
const ConstTensor * m_CellToOutputWeights
Definition: LstmParams.hpp:50
uint32_t m_PadBack
Padding back value in the depth dimension.
const ConstTensor * m_RecurrentToForgetWeights
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
const armnnSerializer::NormalizationDescriptor * NormalizationDescriptorPtr
A ComparisonDescriptor for the ComparisonLayer.
Definition: Descriptors.hpp:89
static GraphPtr LoadGraphFromBinary(const uint8_t *binaryContent, size_t len)
float m_ScaleX
Center size encoding scale x.
bool m_TransposeWeightMatrix
Enable/disable transpose weight matrix.
uint32_t m_PoolWidth
Pooling width value.
bool m_PeepholeEnabled
Enable/disable peephole.
uint32_t GetNumInputs() const
Get the number of views/inputs.
#define CHECK_TENSOR_PTR(TENSOR_PTR)
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
A Convolution2dDescriptor for the Convolution2dLayer.
float m_Alpha
Alpha value for the normalization equation.
uint32_t m_PadLeft
Padding left value in the width dimension.
const armnnSerializer::QLstmDescriptor * QLstmDescriptorPtr
static armnn::UnidirectionalSequenceLstmDescriptor GetUnidirectionalSequenceLstmDescriptor(UnidirectionalSequenceLstmDescriptorPtr descriptor)
bool m_KeepDims
if true then output shape has no change.
float m_HiddenStateScale
Hidden State quantization scale.
const char * EnumNameConstTensorData(ConstTensorData e)
bool m_BiasEnabled
Enable/disable bias.
const ConstTensor * m_CellToInputWeights
Definition: LstmParams.hpp:48
unsigned int GetNumBytes() const
Definition: Tensor.cpp:427
float m_OutputIntermediateScale
Output intermediate quantization scale.
ResizeMethod m_Method
The Interpolation method to use (Bilinear, NearestNeighbor).
float m_Gamma
Gamma, the scale scalar value applied for the normalized tensor. Defaults to 1.0. ...
float m_Beta
Exponentiation value.
BindingPointInfo GetNetworkInputBindingInfo(unsigned int layerId, const std::string &name) const
Retrieve binding info (layer id and tensor info) for the network input identified by the given layer ...
std::vector< unsigned int > m_Size
Size of the slice in each dimension.
armnn::INetworkPtr CreateNetworkFromBinary(const std::vector< uint8_t > &binaryContent)
Create an input network from binary file contents.
The padding fields don&#39;t count and are ignored.
float m_Eps
Value to add to the variance. Used to avoid dividing by zero.
const ConstTensor * m_InputGateBias
Definition: LstmParams.hpp:51
PaddingMethod m_PaddingMethod
The padding method to be used. (Exclude, IgnoreValue).
ArgMinMaxFunction m_Function
Specify if the function is to find Min or Max.
Definition: Descriptors.hpp:81
uint32_t m_DetectionsPerClass
Detections per classes, used in Regular NMS.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
void CheckLayers(Graph &graph)
#define ARMNN_LOG(severity)
Definition: Logging.hpp:205
uint32_t m_PadRight
Padding right value in the width dimension.
const armnnSerializer::SerializedGraph * GetSerializedGraph(const void *buf)
uint32_t m_PadTop
Padding top value in the height dimension.
const ConstTensor * m_RecurrentToCellWeights
Definition: LstmParams.hpp:46
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
A LogicalBinaryDescriptor for the LogicalBinaryLayer.
uint32_t m_PadRight
Padding right value in the width dimension.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
MemoryType GetMemoryArea() const
Definition: Tensor.hpp:305
const ConstTensor * m_ForgetLayerNormWeights
Definition: LstmParams.hpp:58
ReduceOperation m_ReduceOperation
Specifies the reduction operation to execute.
const ConstTensor * m_CellToForgetWeights
Definition: LstmParams.hpp:49
bool m_TimeMajor
Enable/disable time major.
Copyright (c) 2021 ARM Limited and Contributors.
DataLayout m_DataLayout
The data layout to be used (NCDHW, NDHWC).
void IgnoreUnused(Ts &&...)
uint32_t m_PadBottom
Padding bottom value in the height dimension.
uint32_t m_PadFront
Padding front value in the depth dimension.
#define CHECK_GRAPH(GRAPH, LAYERS_INDEX)
uint32_t m_DilationY
Dilation along y axis.
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
const armnnSerializer::SerializedGraph * GraphPtr
std::vector< std::pair< unsigned int, unsigned int > > m_PadList
Specifies the padding values for the input dimension: heightPad{top, bottom} widthPad{left, right}.
uint32_t m_PoolHeight
Pooling height value.
uint32_t m_DilationX
Dilation along x axis.
uint32_t m_DilationY
Dilation factor value for height dimension.
const armnnSerializer::Pooling2dDescriptor * Pooling2dDescriptor
LogicalBinaryOperation m_Operation
Specifies the logical operation to execute.
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
LogicalBinaryOperation
Definition: Types.hpp:118
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:290
const ConstTensor * m_OutputGateBias
Definition: LstmParams.hpp:54
armnn::ComparisonOperation ToComparisonOperation(armnnSerializer::ComparisonOperation operation)
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
static int32_t GetBindingLayerInfo(const GraphPtr &graphPtr, unsigned int layerIndex)
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
uint32_t m_NumOutputs
Number of output tensors.
NormalizationAlgorithmMethod m_NormMethodType
Normalization method algorithm to use (LocalBrightness, LocalContrast).
void SetShape(const TensorShape &newShape)
Definition: Tensor.hpp:193
A ResizeBilinearDescriptor for the ResizeBilinearLayer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
uint32_t m_MaxClassesPerDetection
Maximum numbers of classes per detection, used in Fast NMS.
const armnnSerializer::LayerBase * LayerBaseRawPtr
std::vector< unsigned int > m_Axis
Values for the dimensions to reduce.
A StackDescriptor for the StackLayer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
TensorShape m_TargetShape
Target shape value.
uint32_t m_PoolHeight
Pooling height value.
uint32_t m_PadTop
Padding top value in the height dimension.
uint32_t m_MaxDetections
Maximum numbers of detections.
A PadDescriptor for the PadLayer.
std::vector< TensorRawPtr > TensorRawPtrVector
void Permute(const armnn::TensorShape &dstShape, const armnn::PermutationVector &mappings, const void *src, void *dst, size_t dataTypeSize)
Definition: Permute.cpp:131
#define CHECK_CONST_TENSOR_SIZE(CONST_TENSOR_SIZE, TENSOR_SIZE)
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
const armnnSerializer::UnidirectionalSequenceLstmDescriptor * UnidirectionalSequenceLstmDescriptorPtr
const ConstTensor * m_InputLayerNormWeights
Definition: LstmParams.hpp:57
ComparisonOperation
Definition: Types.hpp:108
uint32_t m_PadBack
Padding back value in the depth dimension.
armnn::INetworkPtr CreateNetworkFromBinary(const std::vector< uint8_t > &binaryContent)
Create an input network from binary file contents.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
ReduceOperation
Definition: Types.hpp:143
bool m_LayerNormEnabled
Enable/disable layer normalization.
const armnnSerializer::LstmDescriptor * LstmDescriptorPtr
armnn::DataLayout ToDataLayout(armnnSerializer::DataLayout dataLayout)
bool CheckShape(const armnn::TensorShape &actual, const std::vector< uint32_t > &expected)
DataType
Definition: Types.hpp:48
float m_NmsIouThreshold
Intersection over union threshold.
const ConstTensor * m_RecurrentToOutputWeights
Definition: LstmParams.hpp:47
static armnn::LstmDescriptor GetLstmDescriptor(LstmDescriptorPtr lstmDescriptor)
An LstmDescriptor for the LstmLayer.
uint32_t m_PadRight
Padding right value in the width dimension.
uint32_t m_DilationX
Dilation factor value for width dimension.
uint32_t m_PadTop
Padding top value in the height dimension.
std::string FileLine() const
Definition: Exceptions.hpp:37
Status SetViewSize(uint32_t view, uint32_t coord, uint32_t value)
Set the size of the views.
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
std::vector< unsigned int > m_Begin
Beginning indices of the slice in each dimension.
bool m_KeepDims
Enable/disable keep dimensions. If true, then the reduced dimensions that are of length 1 are kept...
std::vector< unsigned int > m_BlockShape
Block shape values.
float m_Eps
Epsilon, small scalar value added to variance to avoid dividing by zero. Defaults to 1e-12f...
An output connection slot for a layer.
Definition: INetwork.hpp:40
A L2NormalizationDescriptor for the L2NormalizationLayer.
const ConstTensor * m_ProjectionBias
Definition: LstmParams.hpp:56
static TensorRawPtrVector GetInputs(const GraphPtr &graph, unsigned int layerIndex)
const ConstTensor * m_InputToForgetWeights
An ArgMinMaxDescriptor for ArgMinMaxLayer.
Definition: Descriptors.hpp:67
An OriginsDescriptor for the ConcatLayer.
A ReduceDescriptor for the REDUCE operators.
float m_ProjectionClip
Clipping threshold value for the projection.
A FullyConnectedDescriptor for the FullyConnectedLayer.
BindingPointInfo GetNetworkOutputBindingInfo(unsigned int layerId, const std::string &name) const
Retrieve binding info (layer id and tensor info) for the network output identified by the given layer...
bool m_BiasEnabled
Enable/disable bias.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:327
float m_InputIntermediateScale
Input intermediate quantization scale.
OutputShapeRounding m_OutputShapeRounding
The rounding method for the output shape. (Floor, Ceiling).
uint32_t m_TargetWidth
Target width value.
A GatherDescriptor for the GatherLayer.
uint32_t m_PadBottom
Padding bottom value in the height dimension.
#define CHECK_VALID_SIZE(ACTUAL,...)
bool m_PeepholeEnabled
Enable/disable peephole.
uint32_t m_NumClasses
Number of classes.
#define CHECKED_NON_NEGATIVE(VALUE)
bool m_HalfPixelCenters
Half Pixel Centers.
std::unique_ptr< IDeserializer, void(*)(IDeserializer *parser)> IDeserializerPtr
armnn::ConstTensor ToConstTensor(ConstTensorRawPtr constTensorPtr)
armnn::ActivationFunction ToActivationFunction(armnnSerializer::ActivationFunction function)
uint32_t m_PadTop
Padding top value in the height dimension.
armnn::UnaryOperation ToUnaryOperation(armnnSerializer::UnaryOperation operation)
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
A StandInDescriptor for the StandIn layer.
A QLstmDescriptor for the QLstmLayer.
#define CHECK_CONST_TENSOR_PTR(TENSOR_PTR)
bool m_UseRegularNms
Use Regular NMS.
uint32_t m_PadFront
Padding front value in the depth dimension.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
std::vector< unsigned int > m_BlockShape
Block shape value.
PaddingMode
The padding mode controls whether the padding should be filled with constant values (Constant)...
Definition: Types.hpp:186
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:36
const TensorInfo & GetInfo() const
Definition: Tensor.hpp:295
min(a, max(b, input)) ReLu1 & ReLu6.
#define CHECK_LOCATION()
Definition: Exceptions.hpp:203
uint32_t m_PadLeft
Padding left value in the width dimension.
uint32_t m_TargetHeight
Target height value.
uint32_t m_ActivationFunc
The activation function to use.
A SliceDescriptor for the SliceLayer.
static armnn::Pooling3dDescriptor GetPooling3dDescriptor(Pooling3dDescriptor pooling3dDescriptor, unsigned int layerIndex)
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
A Convolution3dDescriptor for the Convolution3dLayer.
uint32_t m_PadRight
Padding right value in the width dimension.
const ConstTensor * m_RecurrentToInputWeights
float m_ClippingThresCell
Clipping threshold value for the cell state.
unsigned int m_BlockSize
Scalar specifying the input block size. It must be >= 1.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
float m_ForgetIntermediateScale
Forget intermediate quantization scale.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
float m_Beta
Beta, the offset scalar value applied for the normalized tensor. Defaults to 1.0. ...
armnn::ResizeMethod ToResizeMethod(armnnSerializer::ResizeMethod method)
armnn::PaddingMode ToPaddingMode(armnnSerializer::PaddingMode paddingMode)
A Pooling3dDescriptor for the Pooling3dLayer.
uint32_t m_StrideZ
Stride value when proceeding through input for the depth dimension.
std::vector< uint32_t > m_vAxis
The indices of the dimensions to reduce.
float m_ScaleH
Center size encoding scale height.
static armnn::Pooling2dDescriptor GetPooling2dDescriptor(Pooling2dDescriptor pooling2dDescriptor, unsigned int layerIndex)
ComparisonOperation m_Operation
Specifies the comparison operation to execute.
const ConstTensor * m_CellLayerNormWeights
Definition: LstmParams.hpp:59
const ConstTensor * m_ForgetGateBias
Definition: LstmParams.hpp:52
A SpaceToBatchNdDescriptor for the SpaceToBatchNdLayer.
const ConstTensor * m_InputToCellWeights
Definition: LstmParams.hpp:42
DataLayout m_DataLayout
The data layout to be used (NDHWC, NCDHW).
const ConstTensor * m_InputToOutputWeights
Definition: LstmParams.hpp:43
NormalizationAlgorithmChannel m_NormChannelType
Normalization channel algorithm to use (Across, Within).
float m_CellClip
Clipping threshold value for the cell state.
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH, Elu).
Definition: Descriptors.hpp:61
uint32_t m_DilationX
Dilation along x axis.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
const armnnSerializer::TensorInfo * TensorRawPtr
bool m_CifgEnabled
Enable/disable cifg (coupled input & forget gate).
armnn::ArgMinMaxFunction ToArgMinMaxFunction(armnnSerializer::ArgMinMaxFunction function)
uint32_t GetNumInputs() const
Get the number of views/inputs.
uint32_t m_PadLeft
Padding left value in the width dimension.
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
Definition: Optional.hpp:32
bool m_AlignCorners
Aligned corners.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
int32_t m_Axis
The axis in params to gather indices from.
A ElementwiseUnaryDescriptor for the ElementwiseUnaryLayer.
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).
const ConstTensor * m_RecurrentToForgetWeights
Definition: LstmParams.hpp:45
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
uint32_t m_PadLeft
Padding left value in the width dimension.
The padding fields count, but are ignored.
std::vector< std::pair< unsigned int, unsigned int > > m_Crops
The values to crop from the input dimension.
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
static std::string GetLayerName(const GraphPtr &graph, unsigned int index)
uint32_t m_PadTop
Padding top value in the height dimension.
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
uint32_t m_PadTop
Padding top value in the height dimension.
bool m_ProjectionEnabled
Enable/disable the projection layer.
Jarret 2009: Local Contrast Normalization.
ArgMinMaxFunction
Definition: Types.hpp:102
OutputShapeRounding m_OutputShapeRounding
The rounding method for the output shape. (Floor, Ceiling).
uint32_t m_NumInputs
Number of input tensors.
const ConstTensor * m_RecurrentToCellWeights
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
ResizeMethod
Definition: Types.hpp:152
const ConstTensor * m_RecurrentToInputWeights
Definition: LstmParams.hpp:44
A MeanDescriptor for the MeanLayer.
void SetConstant(const bool IsConstant=true)
Marks the data corresponding to this tensor info as constant.
Definition: Tensor.cpp:514
const ConstTensor * m_InputToOutputWeights
UnaryOperation
Definition: Types.hpp:124
static armnn::QLstmDescriptor GetQLstmDescriptor(QLstmDescriptorPtr qLstmDescriptorPtr)
static armnn::TensorInfo OutputShapeOfReshape(const armnn::TensorInfo &inputTensorInfo, const std::vector< uint32_t > &targetDimsIn)
bool m_LayerNormEnabled
Enable/disable layer normalization.
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:35
armnn::TensorInfo ToTensorInfo(TensorRawPtr tensorPtr)
uint32_t m_PadRight
Padding right value in the width dimension.
A TransposeDescriptor for the TransposeLayer.
A StridedSliceDescriptor for the StridedSliceLayer.
uint32_t m_Axis
Axis to apply channel shuffle operation on.
uint32_t GetNumInputs() const
Get the number of views/inputs.
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
int m_Axis
Axis to reduce across the input tensor.
Definition: Descriptors.hpp:83
float m_ScaleY
Center size encoding scale y.
float m_NmsScoreThreshold
NMS score threshold.
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:241
virtual int Connect(IInputSlot &destination)=0
Krichevsky 2012: Local Brightness Normalization.
const char * m_Function
Definition: Exceptions.hpp:16
const char * EnumNameDataType(DataType e)
A Pooling2dDescriptor for the Pooling2dLayer.
const ConstTensor * m_OutputLayerNormWeights
Definition: LstmParams.hpp:60
A NormalizationDescriptor for the NormalizationLayer.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
An InstanceNormalizationDescriptor for InstanceNormalizationLayer.
PaddingMethod m_PaddingMethod
The padding method to be used. (Exclude, IgnoreValue).
A ChannelShuffleDescriptor for the ChannelShuffle operator.
float m_CellIntermediateScale
Cell intermediate quantization scale.
uint32_t m_DilationZ
Dilation along z axis.
float m_B
Beta lower bound value used by the activation functions. (BoundedReLu, Linear, TanH).
Definition: Descriptors.hpp:63
armnn::TensorShape Permuted(const armnn::TensorShape &srcShape, const armnn::PermutationVector &mappings)
Definition: Permute.cpp:98
A SoftmaxDescriptor for the SoftmaxLayer.
float m_Beta
Beta value for the normalization equation.
uint32_t m_StrideZ
Stride value when proceeding through input for the depth dimension.
const armnnSerializer::OriginsDescriptor * GetOriginsDescriptor(const armnnSerializer::SerializedGraph *graph, unsigned int layerIndex)
bool m_CifgEnabled
Enable/disable CIFG (coupled input & forget gate).
uint32_t m_NormSize
Depth radius value.
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
Set the view origin coordinates.
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu, LeakyReLu, Abs, Sqrt, Square, Elu).
Definition: Descriptors.hpp:59
An input connection slot for a layer.
Definition: INetwork.hpp:26
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
constexpr unsigned int MaxNumOfTensorDimensions
Definition: Types.hpp:31
uint32_t m_DilationY
Dilation along y axis.
A FillDescriptor for the FillLayer.
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
uint32_t m_PadLeft
Padding left value in the width dimension.
unsigned int GetNumElements() const
Definition: Tensor.hpp:196
const ConstTensor * m_InputToForgetWeights
Definition: LstmParams.hpp:41
ActivationFunction
Definition: Types.hpp:86
constexpr unsigned int GetDataTypeSize(DataType dataType)
Definition: TypesUtils.hpp:151
A PermuteDescriptor for the PermuteLayer.
const armnnSerializer::Pooling3dDescriptor * Pooling3dDescriptor
uint32_t m_PadRight
Padding right value in the width dimension.
int32_t m_HiddenStateZeroPoint
Hidden State zero point.
bool m_ConstantWeights
Enable/disable constant weights and biases.
const ConstTensor * m_InputToInputWeights
Definition: LstmParams.hpp:40