ArmNN
 20.11
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 
14 #include <armnnUtils/Permute.hpp>
15 #include <armnnUtils/Transpose.hpp>
16 #include <armnn/utility/Assert.hpp>
19 
20 #include <ParserHelper.hpp>
21 #include <VerificationHelpers.hpp>
22 
23 #include <fmt/format.h>
24 
25 #include <fstream>
26 #include <algorithm>
27 #include <limits>
28 #include <numeric>
29 
31 using namespace armnn;
32 using namespace armnnSerializer;
33 
34 namespace armnnDeserializer
35 {
36 
37 namespace
38 {
39 
40 const uint32_t VIRTUAL_LAYER_ID = std::numeric_limits<uint32_t>::max();
41 
42  void CheckGraph(const Deserializer::GraphPtr& graph,
43  unsigned int layersIndex,
44  const CheckLocation& location)
45 {
46  if (graph->layers() == nullptr)
47  {
48  throw ParseException(fmt::format("{0} was called with invalid (null) graph. "
49  "Possible reason is that the graph is not yet loaded and Unpack(ed). "
50  "layers:{1} at {2}",
51  location.m_Function,
52  layersIndex,
53  location.FileLine()));
54  }
55  else if (layersIndex >= graph->layers()->size())
56  {
57  throw ParseException(fmt::format("{0} was called with an invalid layers index. layers:{1} at {2}",
58  location.m_Function,
59  layersIndex,
60  location.FileLine()));
61  }
62 }
63 
64 void CheckLayers(const Deserializer::GraphPtr& graph,
65  unsigned int layersIndex,
66  unsigned int layerIndex,
67  const CheckLocation& location)
68 {
69  if (graph->layers() == nullptr)
70  {
71  throw ParseException(fmt::format("{0} was called with invalid (null) graph. "
72  "Possible reason is that the graph is not yet loaded and Unpack(ed). "
73  "layers:{1} at {2}",
74  location.m_Function,
75  layersIndex,
76  location.FileLine()));
77  }
78  else if (layersIndex >= graph->layers()->size())
79  {
80  throw ParseException(fmt::format("{0} was called with an invalid layers index. "
81  "layers:{1} at {2}",
82  location.m_Function,
83  layersIndex,
84  location.FileLine()));
85  }
86  else if (layerIndex >= graph->layers()[layersIndex].size()
87  && layerIndex != VIRTUAL_LAYER_ID)
88  {
89  throw ParseException(fmt::format("{0} was called with an invalid layer index. "
90  "layers:{1} layer:{2} at {3}",
91  location.m_Function,
92  layersIndex,
93  layerIndex,
94  location.FileLine()));
95  }
96 }
97 
98 void CheckTensorPtr(Deserializer::TensorRawPtr rawPtr,
99  const CheckLocation& location)
100 {
101  if (rawPtr == nullptr)
102  {
103  throw ParseException(fmt::format("{0} was called with a null tensor pointer. at {1}",
104  location.m_Function,
105  location.FileLine()));
106  }
107 }
108 
109 void CheckConstTensorPtr(Deserializer::ConstTensorRawPtr rawPtr,
110  const CheckLocation& location)
111 {
112  if (rawPtr == nullptr)
113  {
114  throw ParseException(fmt::format("{0} was called with a null const tensor pointer. at {1}",
115  location.m_Function,
116  location.FileLine()));
117  }
118 }
119 
120 void CheckConstTensorSize(const unsigned int constTensorSize,
121  const unsigned int tensorSize,
122  const CheckLocation& location)
123 {
124  if (constTensorSize != tensorSize)
125  {
126  throw ParseException(fmt::format("{0} wrong number of components supplied to tensor. at:{1}",
127  location.m_Function,
128  location.FileLine()));
129  }
130 }
131 
132 #define CHECK_TENSOR_PTR(TENSOR_PTR) \
133  CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
134 
135 #define CHECK_CONST_TENSOR_SIZE(CONST_TENSOR_SIZE, TENSOR_SIZE) \
136  CheckConstTensorSize(CONST_TENSOR_SIZE, TENSOR_SIZE, CHECK_LOCATION())
137 
138 #define CHECK_CONST_TENSOR_PTR(TENSOR_PTR) \
139  CheckConstTensorPtr(TENSOR_PTR, CHECK_LOCATION())
140 
141 #define CHECK_LAYERS(GRAPH, LAYERS_INDEX, LAYER_INDEX) \
142  CheckLayers(GRAPH, LAYERS_INDEX, LAYER_INDEX, CHECK_LOCATION())
143 
144 #define CHECK_GRAPH(GRAPH, LAYERS_INDEX) \
145  CheckGraph(GRAPH, LAYERS_INDEX, CHECK_LOCATION())
146 }
147 
148 bool CheckShape(const armnn::TensorShape& actual, const std::vector<uint32_t>& expected)
149 {
150  const unsigned int actualSize = actual.GetNumDimensions();
151  if (actualSize != expected.size())
152  {
153  return false;
154  }
155 
156  for (unsigned int i = 0u; i < actualSize; i++)
157  {
158  if (actual[i] != static_cast<unsigned int>(expected[i]))
159  {
160  return false;
161  }
162  }
163 
164  return true;
165 }
166 
167 Deserializer::Deserializer()
168 : m_Network(nullptr, nullptr),
169 //May require LayerType_Max to be included
170 m_ParserFunctions(Layer_MAX+1, &Deserializer::ParseUnsupportedLayer)
171 {
172  // register supported layers
173  m_ParserFunctions[Layer_AbsLayer] = &Deserializer::ParseAbs;
174  m_ParserFunctions[Layer_ActivationLayer] = &Deserializer::ParseActivation;
175  m_ParserFunctions[Layer_AdditionLayer] = &Deserializer::ParseAdd;
176  m_ParserFunctions[Layer_ArgMinMaxLayer] = &Deserializer::ParseArgMinMax;
177  m_ParserFunctions[Layer_BatchToSpaceNdLayer] = &Deserializer::ParseBatchToSpaceNd;
178  m_ParserFunctions[Layer_BatchNormalizationLayer] = &Deserializer::ParseBatchNormalization;
179  m_ParserFunctions[Layer_ComparisonLayer] = &Deserializer::ParseComparison;
180  m_ParserFunctions[Layer_ConcatLayer] = &Deserializer::ParseConcat;
181  m_ParserFunctions[Layer_ConstantLayer] = &Deserializer::ParseConstant;
182  m_ParserFunctions[Layer_Convolution2dLayer] = &Deserializer::ParseConvolution2d;
183  m_ParserFunctions[Layer_DepthToSpaceLayer] = &Deserializer::ParseDepthToSpace;
184  m_ParserFunctions[Layer_DepthwiseConvolution2dLayer] = &Deserializer::ParseDepthwiseConvolution2d;
185  m_ParserFunctions[Layer_DequantizeLayer] = &Deserializer::ParseDequantize;
186  m_ParserFunctions[Layer_DetectionPostProcessLayer] = &Deserializer::ParseDetectionPostProcess;
187  m_ParserFunctions[Layer_DivisionLayer] = &Deserializer::ParseDivision;
188  m_ParserFunctions[Layer_ElementwiseUnaryLayer] = &Deserializer::ParseElementwiseUnary;
189  m_ParserFunctions[Layer_EqualLayer] = &Deserializer::ParseEqual;
190  m_ParserFunctions[Layer_FullyConnectedLayer] = &Deserializer::ParseFullyConnected;
191  m_ParserFunctions[Layer_FillLayer] = &Deserializer::ParseFill;
192  m_ParserFunctions[Layer_FloorLayer] = &Deserializer::ParseFloor;
193  m_ParserFunctions[Layer_GatherLayer] = &Deserializer::ParseGather;
194  m_ParserFunctions[Layer_GreaterLayer] = &Deserializer::ParseGreater;
195  m_ParserFunctions[Layer_InstanceNormalizationLayer] = &Deserializer::ParseInstanceNormalization;
196  m_ParserFunctions[Layer_L2NormalizationLayer] = &Deserializer::ParseL2Normalization;
197  m_ParserFunctions[Layer_LogicalBinaryLayer] = &Deserializer::ParseLogicalBinary;
198  m_ParserFunctions[Layer_LogSoftmaxLayer] = &Deserializer::ParseLogSoftmax;
199  m_ParserFunctions[Layer_LstmLayer] = &Deserializer::ParseLstm;
200  m_ParserFunctions[Layer_MaximumLayer] = &Deserializer::ParseMaximum;
201  m_ParserFunctions[Layer_MeanLayer] = &Deserializer::ParseMean;
202  m_ParserFunctions[Layer_MinimumLayer] = &Deserializer::ParseMinimum;
203  m_ParserFunctions[Layer_MergeLayer] = &Deserializer::ParseMerge;
204  m_ParserFunctions[Layer_MergerLayer] = &Deserializer::ParseConcat;
205  m_ParserFunctions[Layer_MultiplicationLayer] = &Deserializer::ParseMultiplication;
206  m_ParserFunctions[Layer_NormalizationLayer] = &Deserializer::ParseNormalization;
207  m_ParserFunctions[Layer_PadLayer] = &Deserializer::ParsePad;
208  m_ParserFunctions[Layer_PermuteLayer] = &Deserializer::ParsePermute;
209  m_ParserFunctions[Layer_Pooling2dLayer] = &Deserializer::ParsePooling2d;
210  m_ParserFunctions[Layer_PreluLayer] = &Deserializer::ParsePrelu;
211  m_ParserFunctions[Layer_QLstmLayer] = &Deserializer::ParseQLstm;
212  m_ParserFunctions[Layer_QuantizeLayer] = &Deserializer::ParseQuantize;
213  m_ParserFunctions[Layer_QuantizedLstmLayer] = &Deserializer::ParseQuantizedLstm;
214  m_ParserFunctions[Layer_RankLayer] = &Deserializer::ParseRank;
215  m_ParserFunctions[Layer_ReshapeLayer] = &Deserializer::ParseReshape;
216  m_ParserFunctions[Layer_ResizeBilinearLayer] = &Deserializer::ParseResizeBilinear;
217  m_ParserFunctions[Layer_ResizeLayer] = &Deserializer::ParseResize;
218  m_ParserFunctions[Layer_RsqrtLayer] = &Deserializer::ParseRsqrt;
219  m_ParserFunctions[Layer_SliceLayer] = &Deserializer::ParseSlice;
220  m_ParserFunctions[Layer_SoftmaxLayer] = &Deserializer::ParseSoftmax;
221  m_ParserFunctions[Layer_SpaceToBatchNdLayer] = &Deserializer::ParseSpaceToBatchNd;
222  m_ParserFunctions[Layer_SpaceToDepthLayer] = &Deserializer::ParseSpaceToDepth;
223  m_ParserFunctions[Layer_SplitterLayer] = &Deserializer::ParseSplitter;
224  m_ParserFunctions[Layer_StackLayer] = &Deserializer::ParseStack;
225  m_ParserFunctions[Layer_StandInLayer] = &Deserializer::ParseStandIn;
226  m_ParserFunctions[Layer_StridedSliceLayer] = &Deserializer::ParseStridedSlice;
227  m_ParserFunctions[Layer_SubtractionLayer] = &Deserializer::ParseSubtraction;
228  m_ParserFunctions[Layer_SwitchLayer] = &Deserializer::ParseSwitch;
229  m_ParserFunctions[Layer_TransposeConvolution2dLayer] = &Deserializer::ParseTransposeConvolution2d;
230  m_ParserFunctions[Layer_TransposeLayer] = &Deserializer::ParseTranspose;
231 }
232 
233 Deserializer::LayerBaseRawPtr Deserializer::GetBaseLayer(const GraphPtr& graphPtr, unsigned int layerIndex)
234 {
235  auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type();
236 
237  switch(layerType)
238  {
239  case Layer::Layer_AbsLayer:
240  return graphPtr->layers()->Get(layerIndex)->layer_as_AbsLayer()->base();
241  case Layer::Layer_ActivationLayer:
242  return graphPtr->layers()->Get(layerIndex)->layer_as_ActivationLayer()->base();
243  case Layer::Layer_AdditionLayer:
244  return graphPtr->layers()->Get(layerIndex)->layer_as_AdditionLayer()->base();
245  case Layer::Layer_ArgMinMaxLayer:
246  return graphPtr->layers()->Get(layerIndex)->layer_as_ArgMinMaxLayer()->base();
247  case Layer::Layer_BatchToSpaceNdLayer:
248  return graphPtr->layers()->Get(layerIndex)->layer_as_BatchToSpaceNdLayer()->base();
249  case Layer::Layer_BatchNormalizationLayer:
250  return graphPtr->layers()->Get(layerIndex)->layer_as_BatchNormalizationLayer()->base();
251  case Layer::Layer_ComparisonLayer:
252  return graphPtr->layers()->Get(layerIndex)->layer_as_ComparisonLayer()->base();
253  case Layer::Layer_ConcatLayer:
254  return graphPtr->layers()->Get(layerIndex)->layer_as_ConcatLayer()->base();
255  case Layer::Layer_ConstantLayer:
256  return graphPtr->layers()->Get(layerIndex)->layer_as_ConstantLayer()->base();
257  case Layer::Layer_Convolution2dLayer:
258  return graphPtr->layers()->Get(layerIndex)->layer_as_Convolution2dLayer()->base();
259  case Layer::Layer_DepthToSpaceLayer:
260  return graphPtr->layers()->Get(layerIndex)->layer_as_DepthToSpaceLayer()->base();
261  case Layer::Layer_DepthwiseConvolution2dLayer:
262  return graphPtr->layers()->Get(layerIndex)->layer_as_DepthwiseConvolution2dLayer()->base();
263  case Layer::Layer_DequantizeLayer:
264  return graphPtr->layers()->Get(layerIndex)->layer_as_DequantizeLayer()->base();
265  case Layer::Layer_DetectionPostProcessLayer:
266  return graphPtr->layers()->Get(layerIndex)->layer_as_DetectionPostProcessLayer()->base();
267  case Layer::Layer_DivisionLayer:
268  return graphPtr->layers()->Get(layerIndex)->layer_as_DivisionLayer()->base();
269  case Layer::Layer_EqualLayer:
270  return graphPtr->layers()->Get(layerIndex)->layer_as_EqualLayer()->base();
271  case Layer::Layer_ElementwiseUnaryLayer:
272  return graphPtr->layers()->Get(layerIndex)->layer_as_ElementwiseUnaryLayer()->base();
273  case Layer::Layer_FullyConnectedLayer:
274  return graphPtr->layers()->Get(layerIndex)->layer_as_FullyConnectedLayer()->base();
275  case Layer::Layer_FillLayer:
276  return graphPtr->layers()->Get(layerIndex)->layer_as_FillLayer()->base();
277  case Layer::Layer_FloorLayer:
278  return graphPtr->layers()->Get(layerIndex)->layer_as_FloorLayer()->base();
279  case Layer::Layer_GatherLayer:
280  return graphPtr->layers()->Get(layerIndex)->layer_as_GatherLayer()->base();
281  case Layer::Layer_GreaterLayer:
282  return graphPtr->layers()->Get(layerIndex)->layer_as_GreaterLayer()->base();
283  case Layer::Layer_InputLayer:
284  return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->base();
285  case Layer::Layer_InstanceNormalizationLayer:
286  return graphPtr->layers()->Get(layerIndex)->layer_as_InstanceNormalizationLayer()->base();
287  case Layer::Layer_L2NormalizationLayer:
288  return graphPtr->layers()->Get(layerIndex)->layer_as_L2NormalizationLayer()->base();
289  case Layer::Layer_LogicalBinaryLayer:
290  return graphPtr->layers()->Get(layerIndex)->layer_as_LogicalBinaryLayer()->base();
291  case Layer::Layer_LogSoftmaxLayer:
292  return graphPtr->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->base();
293  case Layer::Layer_LstmLayer:
294  return graphPtr->layers()->Get(layerIndex)->layer_as_LstmLayer()->base();
295  case Layer::Layer_MeanLayer:
296  return graphPtr->layers()->Get(layerIndex)->layer_as_MeanLayer()->base();
297  case Layer::Layer_MinimumLayer:
298  return graphPtr->layers()->Get(layerIndex)->layer_as_MinimumLayer()->base();
299  case Layer::Layer_MaximumLayer:
300  return graphPtr->layers()->Get(layerIndex)->layer_as_MaximumLayer()->base();
301  case Layer::Layer_MergeLayer:
302  return graphPtr->layers()->Get(layerIndex)->layer_as_MergeLayer()->base();
303  case Layer::Layer_MergerLayer:
304  return graphPtr->layers()->Get(layerIndex)->layer_as_MergerLayer()->base();
305  case Layer::Layer_MultiplicationLayer:
306  return graphPtr->layers()->Get(layerIndex)->layer_as_MultiplicationLayer()->base();
307  case Layer::Layer_NormalizationLayer:
308  return graphPtr->layers()->Get(layerIndex)->layer_as_NormalizationLayer()->base();
309  case Layer::Layer_OutputLayer:
310  return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->base();
311  case Layer::Layer_PadLayer:
312  return graphPtr->layers()->Get(layerIndex)->layer_as_PadLayer()->base();
313  case Layer::Layer_PermuteLayer:
314  return graphPtr->layers()->Get(layerIndex)->layer_as_PermuteLayer()->base();
315  case Layer::Layer_Pooling2dLayer:
316  return graphPtr->layers()->Get(layerIndex)->layer_as_Pooling2dLayer()->base();
317  case Layer::Layer_PreluLayer:
318  return graphPtr->layers()->Get(layerIndex)->layer_as_PreluLayer()->base();
319  case Layer::Layer_QLstmLayer:
320  return graphPtr->layers()->Get(layerIndex)->layer_as_QLstmLayer()->base();
321  case Layer::Layer_QuantizeLayer:
322  return graphPtr->layers()->Get(layerIndex)->layer_as_QuantizeLayer()->base();
323  case Layer::Layer_QuantizedLstmLayer:
324  return graphPtr->layers()->Get(layerIndex)->layer_as_QuantizedLstmLayer()->base();
325  case Layer::Layer_RankLayer:
326  return graphPtr->layers()->Get(layerIndex)->layer_as_RankLayer()->base();
327  case Layer::Layer_ReshapeLayer:
328  return graphPtr->layers()->Get(layerIndex)->layer_as_ReshapeLayer()->base();
329  case Layer::Layer_ResizeBilinearLayer:
330  return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeBilinearLayer()->base();
331  case Layer::Layer_ResizeLayer:
332  return graphPtr->layers()->Get(layerIndex)->layer_as_ResizeLayer()->base();
333  case Layer::Layer_RsqrtLayer:
334  return graphPtr->layers()->Get(layerIndex)->layer_as_RsqrtLayer()->base();
335  case Layer::Layer_SliceLayer:
336  return graphPtr->layers()->Get(layerIndex)->layer_as_SliceLayer()->base();
337  case Layer::Layer_SoftmaxLayer:
338  return graphPtr->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->base();
339  case Layer::Layer_SpaceToBatchNdLayer:
340  return graphPtr->layers()->Get(layerIndex)->layer_as_SpaceToBatchNdLayer()->base();
341  case Layer::Layer_SpaceToDepthLayer:
342  return graphPtr->layers()->Get(layerIndex)->layer_as_SpaceToDepthLayer()->base();
343  case Layer::Layer_SplitterLayer:
344  return graphPtr->layers()->Get(layerIndex)->layer_as_SplitterLayer()->base();
345  case Layer::Layer_StackLayer:
346  return graphPtr->layers()->Get(layerIndex)->layer_as_StackLayer()->base();
347  case Layer::Layer_StandInLayer:
348  return graphPtr->layers()->Get(layerIndex)->layer_as_StandInLayer()->base();
349  case Layer::Layer_StridedSliceLayer:
350  return graphPtr->layers()->Get(layerIndex)->layer_as_StridedSliceLayer()->base();
351  case Layer::Layer_SubtractionLayer:
352  return graphPtr->layers()->Get(layerIndex)->layer_as_SubtractionLayer()->base();
353  case Layer::Layer_SwitchLayer:
354  return graphPtr->layers()->Get(layerIndex)->layer_as_SwitchLayer()->base();
355  case Layer::Layer_TransposeConvolution2dLayer:
356  return graphPtr->layers()->Get(layerIndex)->layer_as_TransposeConvolution2dLayer()->base();
357  case Layer::Layer_TransposeLayer:
358  return graphPtr->layers()->Get(layerIndex)->layer_as_TransposeLayer()->base();
359  case Layer::Layer_NONE:
360  default:
361  throw ParseException(fmt::format("Layer type {} not recognized", layerType));
362  }
363 }
364 
365 std::string Deserializer::GetLayerName(const GraphPtr& graph, unsigned int index)
366 {
367  auto layer = GetBaseLayer(graph, index);
368  assert(layer);
369  return layer->layerName()->str();
370 }
371 
372 int32_t Deserializer::GetBindingLayerInfo(const GraphPtr& graphPtr, unsigned int layerIndex)
373 {
374  auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type();
375 
376  if (layerType == Layer::Layer_InputLayer)
377  {
378  return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->layerBindingId();
379  }
380  else if ( layerType == Layer::Layer_OutputLayer )
381  {
382  return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->layerBindingId();
383  }
384  return 0;
385 }
386 
388 {
389  switch (dataLayout)
390  {
391  case armnnSerializer::DataLayout::DataLayout_NHWC:
393  case armnnSerializer::DataLayout::DataLayout_NCHW:
394  default:
396  }
397 }
398 
400 {
401  switch (function)
402  {
403  case armnnSerializer::ActivationFunction_Sigmoid:
405  case armnnSerializer::ActivationFunction_TanH:
407  case armnnSerializer::ActivationFunction_Linear:
409  case armnnSerializer::ActivationFunction_ReLu:
411  case armnnSerializer::ActivationFunction_BoundedReLu:
413  case armnnSerializer::ActivationFunction_LeakyReLu:
415  case armnnSerializer::ActivationFunction_Abs:
417  case armnnSerializer::ActivationFunction_Sqrt:
419  case armnnSerializer::ActivationFunction_Square:
421  case armnnSerializer::ActivationFunction_Elu:
423  case armnnSerializer::ActivationFunction_HardSwish:
425  default:
427  }
428 }
429 
431 {
432  switch (function)
433  {
434  case armnnSerializer::ArgMinMaxFunction::ArgMinMaxFunction_Max:
436  case armnnSerializer::ArgMinMaxFunction::ArgMinMaxFunction_Min:
437  default:
439  }
440 }
441 
443 {
444  switch (operation)
445  {
446  case armnnSerializer::ComparisonOperation::ComparisonOperation_Equal:
448  case armnnSerializer::ComparisonOperation::ComparisonOperation_Greater:
450  case armnnSerializer::ComparisonOperation::ComparisonOperation_GreaterOrEqual:
452  case armnnSerializer::ComparisonOperation::ComparisonOperation_Less:
454  case armnnSerializer::ComparisonOperation::ComparisonOperation_LessOrEqual:
456  case armnnSerializer::ComparisonOperation::ComparisonOperation_NotEqual:
457  default:
459  }
460 }
461 
463 {
464  switch (operation)
465  {
466  case armnnSerializer::LogicalBinaryOperation::LogicalBinaryOperation_LogicalAnd:
468  case armnnSerializer::LogicalBinaryOperation::LogicalBinaryOperation_LogicalOr:
470  default:
471  throw armnn::InvalidArgumentException("Logical Binary operation unknown");
472  }
473 }
474 
476 {
477  switch (operation)
478  {
479  case armnnSerializer::UnaryOperation::UnaryOperation_Abs:
481  case armnnSerializer::UnaryOperation::UnaryOperation_Rsqrt:
483  case armnnSerializer::UnaryOperation::UnaryOperation_Sqrt:
485  case armnnSerializer::UnaryOperation::UnaryOperation_Exp:
487  case armnnSerializer::UnaryOperation::UnaryOperation_Neg:
489  case armnnSerializer::UnaryOperation::UnaryOperation_LogicalNot:
491  default:
492  throw armnn::InvalidArgumentException("Unary operation unknown");
493  }
494 }
495 
497 {
498  switch (method)
499  {
500  case armnnSerializer::ResizeMethod_NearestNeighbor:
502  case armnnSerializer::ResizeMethod_Bilinear:
504  default:
506  }
507 }
508 
510 {
511  armnn::DataType type;
512  CHECK_TENSOR_PTR(tensorPtr);
513 
514  switch (tensorPtr->dataType())
515  {
516  case DataType_QAsymmS8:
518  break;
519  case DataType_QSymmS8:
521  break;
522  case DataType_QuantisedAsymm8:
523  case DataType_QAsymmU8:
525  break;
526  case DataType_QSymmS16:
527  case DataType_QuantisedSymm16:
529  break;
530  case DataType_Signed32:
532  break;
533  case DataType_Float32:
535  break;
536  case DataType_Float16:
538  break;
539  case DataType_Boolean:
541  break;
542  default:
543  {
544  CheckLocation location = CHECK_LOCATION();
545  throw ParseException(fmt::format("Unsupported data type {0} = {1}. {2}",
546  tensorPtr->dataType(),
547  EnumNameDataType(tensorPtr->dataType()),
548  location.AsString()));
549  }
550  }
551 
552  if (tensorPtr->dimensionality() == static_cast<unsigned int>(Dimensionality::Scalar))
553  {
554  float quantizationScale = tensorPtr->quantizationScale();
555  int32_t quantizationOffset = tensorPtr->quantizationOffset();
556 
558  type,
559  quantizationScale,
560  quantizationOffset);
561  }
562 
563  auto dimensions = tensorPtr->dimensions();
564  unsigned int size = dimensions->size();
565  std::vector<unsigned int> outputDims(dimensions->begin(), dimensions->begin() + size);
566 
567  auto quantizationScales = tensorPtr->quantizationScales();
568 
569  if (quantizationScales)
570  {
571  unsigned int quantizationScalesSize = quantizationScales->size();
572  std::vector<float> scales(quantizationScales->begin(), quantizationScales->begin() + quantizationScalesSize);
573  unsigned int quantizationDim = tensorPtr->quantizationDim();
574  armnn::TensorInfo result(size,
575  outputDims.data(),
576  type,
577  scales,
578  quantizationDim);
579  return result;
580  }
581 
582  float quantizationScale = tensorPtr->quantizationScale();
583  int32_t quantizationOffset = tensorPtr->quantizationOffset();
584 
585  // two statements (on purpose) for easier debugging:
586  armnn::TensorInfo result(size,
587  outputDims.data(),
588  type,
589  quantizationScale,
590  quantizationOffset);
591  return result;
592 }
593 
595 {
596  CHECK_CONST_TENSOR_PTR(constTensorPtr);
597  armnn::TensorInfo tensorInfo = ToTensorInfo(constTensorPtr->info());
598 
599  switch (constTensorPtr->data_type())
600  {
601  case ConstTensorData_ByteData:
602  {
603  auto byteData = constTensorPtr->data_as_ByteData()->data();
604  CHECK_CONST_TENSOR_SIZE(byteData->size(), tensorInfo.GetNumElements());
605  return armnn::ConstTensor(tensorInfo, byteData->data());
606  }
607  case ConstTensorData_ShortData:
608  {
609  auto shortData = constTensorPtr->data_as_ShortData()->data();
610  CHECK_CONST_TENSOR_SIZE(shortData->size(), tensorInfo.GetNumElements());
611  return armnn::ConstTensor(tensorInfo, shortData->data());
612  }
613  case ConstTensorData_IntData:
614  {
615  auto intData = constTensorPtr->data_as_IntData()->data();
616  CHECK_CONST_TENSOR_SIZE(intData->size(), tensorInfo.GetNumElements());
617  return armnn::ConstTensor(tensorInfo, intData->data());
618  }
619  case ConstTensorData_LongData:
620  {
621  auto longData = constTensorPtr->data_as_LongData()->data();
622  CHECK_CONST_TENSOR_SIZE(longData->size(), tensorInfo.GetNumElements());
623  return armnn::ConstTensor(tensorInfo, longData->data());
624  }
625  default:
626  {
627  CheckLocation location = CHECK_LOCATION();
628  throw ParseException(fmt::format("Unsupported data type {0} = {1}. {2}",
629  constTensorPtr->data_type(),
630  EnumNameConstTensorData(constTensorPtr->data_type()),
631  location.AsString()));
632  }
633  }
634 }
635 
637  unsigned int layerIndex)
638 {
639  CHECK_LAYERS(graphPtr, 0, layerIndex);
640  auto layer = GetBaseLayer(graphPtr, layerIndex);
641  const auto& numInputs = layer->inputSlots()->size();
642 
643  TensorRawPtrVector result(numInputs);
644 
645  for (unsigned int i=0; i<numInputs; ++i)
646  {
647  auto inputId = CHECKED_NON_NEGATIVE(static_cast<int32_t>
648  (layer->inputSlots()->Get(i)->connection()->sourceLayerIndex()));
649  result[i] = GetBaseLayer(graphPtr, inputId)->outputSlots()->Get(0)->tensorInfo();
650  }
651  return result;
652 }
653 
655  unsigned int layerIndex)
656 {
657  CHECK_LAYERS(graphPtr, 0, layerIndex);
658  auto layer = GetBaseLayer(graphPtr, layerIndex);
659  const auto& numOutputs = layer->outputSlots()->size();
660 
661  TensorRawPtrVector result(numOutputs);
662 
663  for (unsigned int i=0; i<numOutputs; ++i)
664  {
665  result[i] = layer->outputSlots()->Get(i)->tensorInfo();
666  }
667  return result;
668 }
669 
670 void Deserializer::ParseUnsupportedLayer(GraphPtr graph, unsigned int layerIndex)
671 {
672  CHECK_LAYERS(graph, 0, layerIndex);
673  const auto layerName = GetBaseLayer(graph, layerIndex)->layerName()->c_str();
674  throw ParseException(fmt::format("Layer not supported. layerIndex: {0} "
675  "layerName: {1} / {2}",
676  layerIndex,
677  layerName,
678  CHECK_LOCATION().AsString()));
679 }
680 
681 void Deserializer::ResetParser()
682 {
683  m_Network = armnn::INetworkPtr(nullptr, nullptr);
684  m_InputBindings.clear();
685  m_OutputBindings.clear();
686 }
687 
689 {
690  return new Deserializer();
691 }
692 
694 {
696 }
697 
699 {
700  delete parser;
701 }
702 
703 INetworkPtr Deserializer::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
704 {
705  ResetParser();
706  GraphPtr graph = LoadGraphFromBinary(binaryContent.data(), binaryContent.size());
707  return CreateNetworkFromGraph(graph);
708 }
709 
711 {
712  ResetParser();
713  std::vector<uint8_t> content((std::istreambuf_iterator<char>(binaryContent)), std::istreambuf_iterator<char>());
714  GraphPtr graph = LoadGraphFromBinary(content.data(), content.size());
715  return CreateNetworkFromGraph(graph);
716 }
717 
718 Deserializer::GraphPtr Deserializer::LoadGraphFromBinary(const uint8_t* binaryContent, size_t len)
719 {
720  if (binaryContent == nullptr)
721  {
722  throw InvalidArgumentException(fmt::format("Invalid (null) binary content {}",
723  CHECK_LOCATION().AsString()));
724  }
725  flatbuffers::Verifier verifier(binaryContent, len);
726  if (verifier.VerifyBuffer<SerializedGraph>() == false)
727  {
728  throw ParseException(fmt::format("Buffer doesn't conform to the expected Armnn "
729  "flatbuffers format. size:{0} {1}",
730  len,
731  CHECK_LOCATION().AsString()));
732  }
733  return GetSerializedGraph(binaryContent);
734 }
735 
736 INetworkPtr Deserializer::CreateNetworkFromGraph(GraphPtr graph)
737 {
738  m_Network = INetwork::Create();
739  ARMNN_ASSERT(graph != nullptr);
740  unsigned int layerIndex = 0;
741  for (AnyLayer const* layer : *graph->layers())
742  {
743  if (layer->layer_type() != Layer_InputLayer &&
744  layer->layer_type() != Layer_OutputLayer)
745  {
746  // lookup and call the parser function
747  auto& parserFunction = m_ParserFunctions[layer->layer_type()];
748  (this->*parserFunction)(graph, layerIndex);
749  }
750  ++layerIndex;
751  }
752 
753  SetupInputLayers(graph);
754  SetupOutputLayers(graph);
755 
756  // establish the connections from the layer outputs to the inputs of the subsequent layers
757  for (auto&& graphIt : m_GraphConnections)
758  {
759  Connections& connections = graphIt.second;
760  for (auto&& outputIt : connections.outputSlots)
761  {
762  const unsigned int outputSlotIndex = outputIt.first;
763  IOutputSlot* outputSlot = outputIt.second;
764  if (connections.inputSlots.find(outputSlotIndex) != connections.inputSlots.end())
765  {
766  for (IInputSlot* inputSlot : connections.inputSlots[outputSlotIndex])
767  {
768  outputSlot->Connect(*inputSlot);
769  }
770  }
771  }
772  }
773 
774  return std::move(m_Network);
775 }
776 
778  const std::string& name) const
779 {
780  IgnoreUnused(layerIndex);
781  for (auto inputBinding : m_InputBindings)
782  {
783  if (inputBinding.first == name)
784  {
785  return inputBinding.second;
786  }
787  }
788  throw ParseException(fmt::format("No input binding found for layer:{0} / {1}",
789  name,
790  CHECK_LOCATION().AsString()));
791 }
792 
794  const std::string& name) const
795 {
796  IgnoreUnused(layerIndex);
797  for (auto outputBinding : m_OutputBindings)
798  {
799  if (outputBinding.first == name)
800  {
801  return outputBinding.second;
802  }
803  }
804  throw ParseException(fmt::format("No output binding found for layer:{0} / {1}",
805  name,
806  CHECK_LOCATION().AsString()));
807 }
808 
809 unsigned int Deserializer::GetInputLayerInVector(GraphPtr graph, int targetId)
810 {
811  for (unsigned int i = 0; i < graph->layers()->size(); i++)
812  {
813  auto layer = graph->layers()->Get(i);
814  if (layer->layer_type() == Layer::Layer_InputLayer)
815  {
816  auto layerBindingId = layer->layer_as_InputLayer()->base()->layerBindingId();
817  if (layerBindingId == targetId)
818  {
819  return i;
820  }
821  }
822  }
823  throw ParseException("Input layer with given layerBindingId not found");
824 }
825 
826 unsigned int Deserializer::GetOutputLayerInVector(GraphPtr graph, int targetId)
827 {
828  for (unsigned int i = 0; i < graph->layers()->size(); i++)
829  {
830  auto layer = graph->layers()->Get(i);
831  if (layer->layer_type() == Layer::Layer_OutputLayer)
832  {
833  auto layerBindingId = layer->layer_as_OutputLayer()->base()->layerBindingId();
834  if (layerBindingId == targetId)
835  {
836  return i;
837  }
838  }
839  }
840  throw ParseException("Output layer with given layerBindingId not found");
841 }
842 
843 unsigned int Deserializer::GetLayerIndexInVector(GraphPtr graph, unsigned int targetIndex)
844 {
845  for (unsigned int i = 0; i < graph->layers()->size(); i++)
846  {
847  LayerBaseRawPtr layer = GetBaseLayer(graph, i);
848  if (layer->index() == targetIndex)
849  {
850  return i;
851  }
852  }
853  throw ParseException("Layer with given index not found");
854 }
855 
856 Deserializer::FeatureVersions Deserializer::GetFeatureVersions(GraphPtr graph)
857 {
858  Deserializer::FeatureVersions versions;
859 
860  if (graph->featureVersions())
861  {
862  versions.m_BindingIdScheme = graph->featureVersions()->bindingIdsScheme();
863  }
864 
865  return versions;
866 }
867 
868 void Deserializer::SetupInputLayers(GraphPtr graph)
869 {
870  CHECK_GRAPH(graph, 0);
871  const unsigned int numInputs = graph->inputIds()->size();
872  m_InputBindings.clear();
873  m_InputBindings.reserve(numInputs);
874 
875  for (unsigned int i = 0; i < numInputs; i++)
876  {
877  unsigned int inputLayerIndex = 0xFFFFFFFF;
878  if (GetFeatureVersions(graph).m_BindingIdScheme == 0)
879  {
880  const unsigned int inputId = armnn::numeric_cast<unsigned int>(graph->inputIds()->Get(i));
881  inputLayerIndex = GetLayerIndexInVector(graph, inputId);
882  }
883  else
884  {
885  const int inputId = graph->inputIds()->Get(i);
886  inputLayerIndex = GetInputLayerInVector(graph, inputId);
887  }
888 
889  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, inputLayerIndex);
890 
891  // GetBindingLayerInfo expect the index to be index in the vector not index property on each layer base
892  LayerBindingId bindingId = GetBindingLayerInfo(graph, inputLayerIndex);
893  ARMNN_ASSERT_MSG(baseLayer->layerName()->c_str(), "Input has no name.");
894 
895  IConnectableLayer* inputLayer =
896  m_Network->AddInputLayer(bindingId, baseLayer->layerName()->c_str());
897 
898  const armnn::TensorInfo& tensorInfo = ToTensorInfo(baseLayer->outputSlots()->Get(0)->tensorInfo());
899  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
900  RegisterOutputSlots(graph, inputLayerIndex, inputLayer);
901 
902  BindingPointInfo bindingInfo = {bindingId, tensorInfo};
903  m_InputBindings.push_back(std::make_pair(baseLayer->layerName()->c_str(), bindingInfo));
904  }
905 }
906 
907 void Deserializer::SetupOutputLayers(GraphPtr graph)
908 {
909  CHECK_GRAPH(graph, 0);
910  const unsigned int numOutputs = graph->outputIds()->size();
911  m_OutputBindings.clear();
912  m_OutputBindings.reserve(numOutputs);
913 
914  for (unsigned int i = 0; i < numOutputs; i++)
915  {
916  unsigned int outputLayerIndex = 0xFFFFFFFF;
917  if (GetFeatureVersions(graph).m_BindingIdScheme == 0)
918  {
919  const unsigned int outputId = armnn::numeric_cast<unsigned int>(graph->outputIds()->Get(i));
920  outputLayerIndex = GetLayerIndexInVector(graph, outputId);
921  }
922  else
923  {
924  const int outputId = graph->outputIds()->Get(i);
925  outputLayerIndex = GetOutputLayerInVector(graph, outputId);
926  }
927 
928  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, outputLayerIndex);
929 
930  // GetBindingLayerInfo expect the index to be index in the vector not index property on each layer base
931  LayerBindingId bindingId = GetBindingLayerInfo(graph, outputLayerIndex);
932  ARMNN_ASSERT_MSG(baseLayer->layerName()->c_str(), "Output has no name.");
933 
934  IConnectableLayer* outputLayer =
935  m_Network->AddOutputLayer(bindingId, baseLayer->layerName()->c_str());
936 
937  RegisterInputSlots(graph, outputLayerIndex, outputLayer);
938 
939  unsigned int sourceLayerIndex =
940  GetLayerIndexInVector(graph, baseLayer->inputSlots()->Get(0)->connection()->sourceLayerIndex());
941  LayerBaseRawPtr sourceBaseLayer = GetBaseLayer(graph, sourceLayerIndex);
942  const armnn::TensorInfo& tensorInfo = ToTensorInfo(sourceBaseLayer->outputSlots()->Get(i)->tensorInfo());
943 
944  BindingPointInfo bindingInfo = {bindingId, tensorInfo};
945  m_OutputBindings.push_back(std::make_pair(baseLayer->layerName()->c_str(), bindingInfo));
946  }
947 }
948 
949 void Deserializer::RegisterOutputSlots(GraphPtr graph,
950  uint32_t layerIndex,
951  IConnectableLayer* layer)
952 {
953  CHECK_LAYERS(graph, 0, layerIndex);
954  ARMNN_ASSERT(layer != nullptr);
955  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, layerIndex);
956  if (baseLayer->outputSlots()->size() != layer->GetNumOutputSlots())
957  {
958  throw ParseException(fmt::format("The number of outputslots ({0}) does not match the number expected ({1})"
959  " for layer index: {2} {3}",
960  baseLayer->outputSlots()->size(),
961  layer->GetNumOutputSlots(),
962  layerIndex,
963  CHECK_LOCATION().AsString()));
964  }
965 
966  for (unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i)
967  {
968  const unsigned int slotIndex = baseLayer->outputSlots()->Get(i)->index();
969  armnn::IOutputSlot* outputSlot = &(layer->GetOutputSlot(slotIndex));
970  // layerIndex is not necessarily the same as baseLayer->index(). The latter is needed here
971  RegisterOutputSlotOfConnection(baseLayer->index(), slotIndex, outputSlot);
972  }
973 }
974 
975 void Deserializer::RegisterInputSlots(GraphPtr graph,
976  uint32_t layerIndex,
978 {
979  CHECK_LAYERS(graph, 0, layerIndex);
980  ARMNN_ASSERT(layer != nullptr);
981  LayerBaseRawPtr baseLayer = GetBaseLayer(graph, layerIndex);
982  if (baseLayer->inputSlots()->size() != layer->GetNumInputSlots())
983  {
984  throw ParseException(fmt::format("The number of inputslots ({0}) does not match the number expected ({1})"
985  " for layer index:{2} {3}",
986  baseLayer->inputSlots()->size(),
987  layer->GetNumInputSlots(),
988  layerIndex,
989  CHECK_LOCATION().AsString()));
990  }
991 
992  for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
993  {
994  auto fbInputSlot = baseLayer->inputSlots()->Get(i);
995  auto fbConnection = fbInputSlot->connection();
996  armnn::IInputSlot* inputSlot = &(layer->GetInputSlot(fbInputSlot->index()));
997  RegisterInputSlotOfConnection(fbConnection->sourceLayerIndex(), fbConnection->outputSlotIndex(), inputSlot);
998  }
999 }
1000 
1001 void Deserializer::RegisterInputSlotOfConnection(uint32_t sourceLayerIndex,
1002  uint32_t outputSlotIndex,
1003  armnn::IInputSlot* inputSlot)
1004 {
1005  if (m_GraphConnections.find(sourceLayerIndex) == m_GraphConnections.end())
1006  {
1007  m_GraphConnections[sourceLayerIndex] = Connections();
1008  }
1009 
1010  Connections& connections = m_GraphConnections[sourceLayerIndex];
1011  if (connections.inputSlots.find(outputSlotIndex) == connections.inputSlots.end())
1012  {
1013  connections.inputSlots[outputSlotIndex] = {inputSlot};
1014  }
1015  else
1016  {
1017  connections.inputSlots[outputSlotIndex].push_back(inputSlot);
1018  }
1019 }
1020 
1021 void Deserializer::RegisterOutputSlotOfConnection(uint32_t sourceLayerIndex,
1022  uint32_t outputSlotIndex,
1023  armnn::IOutputSlot* outputSlot)
1024 {
1025  if (m_GraphConnections.find(sourceLayerIndex) == m_GraphConnections.end())
1026  {
1027  m_GraphConnections[sourceLayerIndex] = Connections();
1028  }
1029 
1030  Connections& connections = m_GraphConnections[sourceLayerIndex];
1031  if (connections.outputSlots.find(outputSlotIndex) != connections.outputSlots.end())
1032  {
1033  throw ParseException("Same output slot index processed twice");
1034  }
1035 
1036  connections.outputSlots[outputSlotIndex] = outputSlot;
1037 }
1038 
1039 void Deserializer::ParseAbs(armnnDeserializer::Deserializer::GraphPtr graph, unsigned int layerIndex)
1040 {
1041  CHECK_LAYERS(graph, 0, layerIndex);
1042  auto inputs = GetInputs(graph, layerIndex);
1043  CHECK_LOCATION();
1044  CHECK_VALID_SIZE(inputs.size(), 1);
1045 
1046  auto outputs = GetOutputs(graph, layerIndex);
1047  CHECK_VALID_SIZE(outputs.size(), 1);
1048 
1049  auto layerName = GetLayerName(graph, layerIndex);
1050 
1052  IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
1053  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1054  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1055 
1056  RegisterInputSlots(graph, layerIndex, layer);
1057  RegisterOutputSlots(graph, layerIndex, layer);
1058 }
1059 
1060 void Deserializer::ParseActivation(GraphPtr graph, unsigned int layerIndex)
1061 {
1062  CHECK_LAYERS(graph, 0, layerIndex);
1063  auto inputs = GetInputs(graph, layerIndex);
1064  CHECK_LOCATION();
1065  CHECK_VALID_SIZE(inputs.size(), 1);
1066 
1067  auto outputs = GetOutputs(graph, layerIndex);
1068  CHECK_VALID_SIZE(outputs.size(), 1);
1069 
1070  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ActivationLayer();
1071  auto layerName = GetLayerName(graph, layerIndex);
1072  auto serializerDescriptor = serializerLayer->descriptor();
1073 
1074  armnn::ActivationDescriptor descriptor;
1075  descriptor.m_Function = ToActivationFunction(serializerDescriptor->activationFunction());
1076  descriptor.m_A = serializerDescriptor->a();
1077  descriptor.m_B = serializerDescriptor->b();
1078 
1079  IConnectableLayer* layer = m_Network->AddActivationLayer(descriptor,
1080  layerName.c_str());
1081  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1082  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1083 
1084  RegisterInputSlots(graph, layerIndex, layer);
1085  RegisterOutputSlots(graph, layerIndex, layer);
1086 }
1087 
1088 void Deserializer::ParseAdd(GraphPtr graph, unsigned int layerIndex)
1089 {
1090  CHECK_LAYERS(graph, 0, layerIndex);
1091  auto inputs = GetInputs(graph, layerIndex);
1092  CHECK_LOCATION();
1093  CHECK_VALID_SIZE(inputs.size(), 2);
1094 
1095  auto outputs = GetOutputs(graph, layerIndex);
1096  CHECK_VALID_SIZE(outputs.size(), 1);
1097 
1098  auto layerName = GetLayerName(graph, layerIndex);
1099  IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
1100 
1101  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1102  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1103 
1104  RegisterInputSlots(graph, layerIndex, layer);
1105  RegisterOutputSlots(graph, layerIndex, layer);
1106 }
1107 
1108 void Deserializer::ParseArgMinMax(GraphPtr graph, unsigned int layerIndex)
1109 {
1110  CHECK_LAYERS(graph, 0, layerIndex);
1111  auto inputs = GetInputs(graph, layerIndex);
1112  CHECK_LOCATION();
1113  CHECK_VALID_SIZE(inputs.size(), 1);
1114 
1115  auto outputs = GetOutputs(graph, layerIndex);
1116  CHECK_VALID_SIZE(outputs.size(), 1);
1117 
1118  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ArgMinMaxLayer();
1119  auto serializerDescriptor = serializerLayer->descriptor();
1120 
1121  armnn::ArgMinMaxDescriptor descriptor;
1122  descriptor.m_Function = ToArgMinMaxFunction(serializerDescriptor->argMinMaxFunction());
1123  descriptor.m_Axis = serializerDescriptor->axis();
1124  auto layerName = GetLayerName(graph, layerIndex);
1125  IConnectableLayer* layer = m_Network->AddArgMinMaxLayer(descriptor, layerName.c_str());
1126 
1127  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1128  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1129 
1130  RegisterInputSlots(graph, layerIndex, layer);
1131  RegisterOutputSlots(graph, layerIndex, layer);
1132 }
1133 
1134 void Deserializer::ParseBatchToSpaceNd(GraphPtr graph, unsigned int layerIndex)
1135 {
1136  CHECK_LAYERS(graph, 0, layerIndex);
1137 
1138  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
1139  CHECK_VALID_SIZE(inputs.size(), 1);
1140 
1141  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
1142  CHECK_VALID_SIZE(outputs.size(), 1);
1143 
1144  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_BatchToSpaceNdLayer()->descriptor();
1145  auto flatBufferCrops = flatBufferDescriptor->crops();
1146  auto flatBufferBlockShape = flatBufferDescriptor->blockShape();
1147 
1148  if (flatBufferCrops->Length() % 2 != 0)
1149  {
1150  throw ParseException(fmt::format("The size of crops must be divisible by 2 {}", CHECK_LOCATION().AsString()));
1151  }
1152 
1153  std::vector<std::pair<unsigned int, unsigned int>> crops;
1154  crops.reserve(flatBufferCrops->Length() / 2);
1155  for (unsigned int i = 0; i < flatBufferCrops->Length() - 1; i += 2)
1156  {
1157  crops.emplace_back(flatBufferCrops->Get(i), flatBufferCrops->Get(i+1));
1158  }
1159 
1161  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
1162  descriptor.m_BlockShape =
1163  std::vector<unsigned int>(flatBufferBlockShape->begin(), flatBufferBlockShape->end());
1164  descriptor.m_Crops = crops;
1165 
1166  auto layerName = GetLayerName(graph, layerIndex);
1167  IConnectableLayer* layer = m_Network->AddBatchToSpaceNdLayer(descriptor, layerName.c_str());
1168 
1169  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1170  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1171 
1172  RegisterInputSlots(graph, layerIndex, layer);
1173  RegisterOutputSlots(graph, layerIndex, layer);
1174 }
1175 
1176 void Deserializer::ParseBatchNormalization(GraphPtr graph, unsigned int layerIndex)
1177 {
1178  CHECK_LAYERS(graph, 0, layerIndex);
1179 
1180  auto inputs = GetInputs(graph, layerIndex);
1181  CHECK_VALID_SIZE(inputs.size(), 1);
1182 
1183  auto outputs = GetOutputs(graph, layerIndex);
1184  CHECK_VALID_SIZE(outputs.size(), 1);
1185  auto outputInfo = ToTensorInfo(outputs[0]);
1186 
1187  auto layerName = GetLayerName(graph, layerIndex);
1188 
1189  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_BatchNormalizationLayer();
1190  auto serializerDescriptor = serializerLayer->descriptor();
1191 
1193  descriptor.m_Eps = serializerDescriptor->eps();
1194  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
1195 
1196  armnn::ConstTensor mean = ToConstTensor(serializerLayer->mean());
1197  armnn::ConstTensor variance = ToConstTensor(serializerLayer->variance());
1198  armnn::ConstTensor beta = ToConstTensor(serializerLayer->beta());
1199  armnn::ConstTensor gamma = ToConstTensor(serializerLayer->gamma());
1200 
1201  IConnectableLayer* layer = m_Network->AddBatchNormalizationLayer(descriptor,
1202  mean,
1203  variance,
1204  beta,
1205  gamma,
1206  layerName.c_str());
1207  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1208 
1209  RegisterInputSlots(graph, layerIndex, layer);
1210  RegisterOutputSlots(graph, layerIndex, layer);
1211 }
1212 
1213 void Deserializer::ParseConstant(GraphPtr graph, unsigned int layerIndex)
1214 {
1215  CHECK_LAYERS(graph, 0, layerIndex);
1216  CHECK_LOCATION();
1217 
1218  auto outputs = GetOutputs(graph, layerIndex);
1219  CHECK_VALID_SIZE(outputs.size(), 1);
1220 
1221  auto layerName = GetLayerName(graph, layerIndex);
1222 
1223  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_ConstantLayer();
1224  auto serializerInput = serializerLayer->input();
1225 
1226  armnn::ConstTensor input = ToConstTensor(serializerInput);
1227 
1228  IConnectableLayer* layer = m_Network->AddConstantLayer(input, layerName.c_str());
1229 
1230  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1231  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1232 
1233  RegisterOutputSlots(graph, layerIndex, layer);
1234 }
1235 
1236 void Deserializer::ParseConvolution2d(GraphPtr graph, unsigned int layerIndex)
1237 {
1238  CHECK_LAYERS(graph, 0, layerIndex);
1239  auto inputs = GetInputs(graph, layerIndex);
1240  CHECK_LOCATION();
1241  CHECK_VALID_SIZE(inputs.size(), 1);
1242 
1243  auto outputs = GetOutputs(graph, layerIndex);
1244  CHECK_VALID_SIZE(outputs.size(), 1);
1245 
1246  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_Convolution2dLayer();
1247  auto layerName = GetLayerName(graph, layerIndex);
1248  auto serializerDescriptor = serializerLayer->descriptor();
1249 
1250  armnn::Convolution2dDescriptor descriptor;
1251  descriptor.m_PadLeft = serializerDescriptor->padLeft();
1252  descriptor.m_PadRight = serializerDescriptor->padRight();
1253  descriptor.m_PadTop = serializerDescriptor->padTop();
1254  descriptor.m_PadBottom = serializerDescriptor->padBottom();
1255  descriptor.m_StrideX = serializerDescriptor->strideX();
1256  descriptor.m_StrideY = serializerDescriptor->strideY();;
1257  descriptor.m_DilationX = serializerDescriptor->dilationX();
1258  descriptor.m_DilationY = serializerDescriptor->dilationY();;
1259  descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();;
1260  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
1261 
1262  armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights());
1263  armnn::ConstTensor biases;
1264 
1266  if (descriptor.m_BiasEnabled)
1267  {
1268  biases = ToConstTensor(serializerLayer->biases());
1269  optionalBiases = armnn::Optional<armnn::ConstTensor>(biases);
1270  }
1271  IConnectableLayer* layer = m_Network->AddConvolution2dLayer(descriptor,
1272  weights,
1273  optionalBiases,
1274  layerName.c_str());
1275  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1276  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1277 
1278  RegisterInputSlots(graph, layerIndex, layer);
1279  RegisterOutputSlots(graph, layerIndex, layer);
1280 }
1281 
1282 void Deserializer::ParseDepthToSpace(GraphPtr graph, unsigned int layerIndex)
1283 {
1284  CHECK_LAYERS(graph, 0, layerIndex);
1285 
1286  auto inputs = GetInputs(graph, layerIndex);
1287  CHECK_VALID_SIZE(inputs.size(), 1);
1288 
1289  auto outputs = GetOutputs(graph, layerIndex);
1290  CHECK_VALID_SIZE(outputs.size(), 1);
1291 
1292  auto fbDescriptor = graph->layers()->Get(layerIndex)->layer_as_DepthToSpaceLayer()->descriptor();
1293 
1294  armnn::DepthToSpaceDescriptor descriptor;
1295  descriptor.m_BlockSize = fbDescriptor->blockSize();
1296  descriptor.m_DataLayout = ToDataLayout(fbDescriptor->dataLayout());
1297 
1298  auto layerName = GetLayerName(graph, layerIndex);
1299  IConnectableLayer* layer = m_Network->AddDepthToSpaceLayer(descriptor, layerName.c_str());
1300 
1301  armnn::TensorInfo outputInfo = ToTensorInfo(outputs[0]);
1302  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1303 
1304  RegisterInputSlots(graph, layerIndex, layer);
1305  RegisterOutputSlots(graph, layerIndex, layer);
1306 }
1307 
1308 void Deserializer::ParseDepthwiseConvolution2d(GraphPtr graph, unsigned int layerIndex)
1309 {
1310  CHECK_LAYERS(graph, 0, layerIndex);
1311  auto inputs = GetInputs(graph, layerIndex);
1312  CHECK_LOCATION();
1313  CHECK_VALID_SIZE(inputs.size(), 1);
1314 
1315  auto outputs = GetOutputs(graph, layerIndex);
1316  CHECK_VALID_SIZE(outputs.size(), 1);
1317 
1318  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_DepthwiseConvolution2dLayer();
1319  auto layerName = GetLayerName(graph, layerIndex);
1320  auto serializerDescriptor = serializerLayer->descriptor();
1321 
1323  descriptor.m_PadLeft = serializerDescriptor->padLeft();
1324  descriptor.m_PadRight = serializerDescriptor->padRight();
1325  descriptor.m_PadTop = serializerDescriptor->padTop();
1326  descriptor.m_PadBottom = serializerDescriptor->padBottom();
1327  descriptor.m_StrideX = serializerDescriptor->strideX();
1328  descriptor.m_StrideY = serializerDescriptor->strideY();
1329  descriptor.m_DilationX = serializerDescriptor->dilationX();
1330  descriptor.m_DilationY = serializerDescriptor->dilationY();
1331  descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();;
1332  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
1333 
1334  armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights());
1335  armnn::ConstTensor biases;
1336 
1338  if (descriptor.m_BiasEnabled)
1339  {
1340  biases = ToConstTensor(serializerLayer->biases());
1341  optionalBiases = armnn::Optional<armnn::ConstTensor>(biases);
1342  }
1343  IConnectableLayer* layer = m_Network->AddDepthwiseConvolution2dLayer(descriptor,
1344  weights,
1345  optionalBiases,
1346  layerName.c_str());
1347 
1348  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1349  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1350 
1351  RegisterInputSlots(graph, layerIndex, layer);
1352  RegisterOutputSlots(graph, layerIndex, layer);
1353 }
1354 
1355 void Deserializer::ParseDetectionPostProcess(GraphPtr graph, unsigned int layerIndex)
1356 {
1357  CHECK_LAYERS(graph, 0, layerIndex);
1358  auto inputs = GetInputs(graph, layerIndex);
1359  CHECK_LOCATION();
1360  CHECK_VALID_SIZE(inputs.size(), 2);
1361 
1362  auto outputs = GetOutputs(graph, layerIndex);
1363  CHECK_VALID_SIZE(outputs.size(), 4);
1364 
1365  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_DetectionPostProcessLayer();
1366  auto layerName = GetLayerName(graph, layerIndex);
1367  auto flatBufferDescriptor = flatBufferLayer->descriptor();
1368 
1370  descriptor.m_MaxDetections = flatBufferDescriptor->maxDetections();
1371  descriptor.m_MaxClassesPerDetection = flatBufferDescriptor->maxClassesPerDetection();
1372  descriptor.m_DetectionsPerClass = flatBufferDescriptor->detectionsPerClass();
1373  descriptor.m_NmsScoreThreshold = flatBufferDescriptor->nmsScoreThreshold();
1374  descriptor.m_NmsIouThreshold = flatBufferDescriptor->nmsIouThreshold();
1375  descriptor.m_NumClasses = flatBufferDescriptor->numClasses();
1376  descriptor.m_UseRegularNms = flatBufferDescriptor->useRegularNms();
1377  descriptor.m_ScaleX = flatBufferDescriptor->scaleX();
1378  descriptor.m_ScaleY = flatBufferDescriptor->scaleY();
1379  descriptor.m_ScaleW = flatBufferDescriptor->scaleW();
1380  descriptor.m_ScaleH = flatBufferDescriptor->scaleH();
1381 
1382  armnn::ConstTensor anchors = ToConstTensor(flatBufferLayer->anchors());
1383 
1384  IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(descriptor,
1385  anchors,
1386  layerName.c_str());
1387 
1388  for (unsigned int i = 0; i < 4; i++)
1389  {
1390  layer->GetOutputSlot(i).SetTensorInfo(ToTensorInfo(outputs[i]));
1391  }
1392 
1393  RegisterInputSlots(graph, layerIndex, layer);
1394  RegisterOutputSlots(graph, layerIndex, layer);
1395 }
1396 
1397 void Deserializer::ParseDivision(GraphPtr graph, unsigned int layerIndex)
1398 {
1399  CHECK_LAYERS(graph, 0, layerIndex);
1400  auto inputs = GetInputs(graph, layerIndex);
1401  CHECK_LOCATION();
1402  CHECK_VALID_SIZE(inputs.size(), 2);
1403 
1404  auto outputs = GetOutputs(graph, layerIndex);
1405  CHECK_VALID_SIZE(outputs.size(), 1);
1406 
1407  auto layerName = GetLayerName(graph, layerIndex);
1408  IConnectableLayer* layer = m_Network->AddDivisionLayer(layerName.c_str());
1409 
1410  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1411  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1412 
1413  RegisterInputSlots(graph, layerIndex, layer);
1414  RegisterOutputSlots(graph, layerIndex, layer);
1415 }
1416 
1417 void Deserializer::ParseEqual(GraphPtr graph, unsigned int layerIndex)
1418 {
1419  CHECK_LAYERS(graph, 0, layerIndex);
1420  auto inputs = GetInputs(graph, layerIndex);
1421  CHECK_LOCATION();
1422  CHECK_VALID_SIZE(inputs.size(), 2);
1423 
1424  auto outputs = GetOutputs(graph, layerIndex);
1425  CHECK_VALID_SIZE(outputs.size(), 1);
1426 
1427  auto layerName = GetLayerName(graph, layerIndex);
1429  IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str());
1430 
1431  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1432  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1433 
1434  RegisterInputSlots(graph, layerIndex, layer);
1435  RegisterOutputSlots(graph, layerIndex, layer);
1436 }
1437 
1438 void Deserializer::ParseFill(GraphPtr graph, unsigned int layerIndex)
1439 {
1440  CHECK_LAYERS(graph, 0, layerIndex);
1441  auto inputs = GetInputs(graph, layerIndex);
1442  CHECK_LOCATION();
1443  CHECK_VALID_SIZE(inputs.size(), 1);
1444 
1445  auto outputs = GetOutputs(graph, layerIndex);
1446  CHECK_VALID_SIZE(outputs.size(), 1);
1447 
1448  auto layerName = GetLayerName(graph, layerIndex);
1449  armnn::FillDescriptor descriptor(1.0f);
1450  IConnectableLayer* layer = m_Network->AddFillLayer(descriptor, layerName.c_str());
1451 
1452  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1453  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1454 
1455  RegisterInputSlots(graph, layerIndex, layer);
1456  RegisterOutputSlots(graph, layerIndex, layer);
1457 }
1458 
1459 void Deserializer::ParseGreater(GraphPtr graph, unsigned int layerIndex)
1460 {
1461  CHECK_LAYERS(graph, 0, layerIndex);
1462  auto inputs = GetInputs(graph, layerIndex);
1463  CHECK_LOCATION();
1464  CHECK_VALID_SIZE(inputs.size(), 2);
1465 
1466  auto outputs = GetOutputs(graph, layerIndex);
1467  CHECK_VALID_SIZE(outputs.size(), 1);
1468 
1469  auto layerName = GetLayerName(graph, layerIndex);
1471  IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str());
1472 
1473  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1474  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1475 
1476  RegisterInputSlots(graph, layerIndex, layer);
1477  RegisterOutputSlots(graph, layerIndex, layer);
1478 }
1479 
1480 void Deserializer::ParseInstanceNormalization(GraphPtr graph, unsigned int layerIndex)
1481 {
1482  CHECK_LAYERS(graph, 0, layerIndex);
1483 
1484  auto inputs = GetInputs(graph, layerIndex);
1485  CHECK_VALID_SIZE(inputs.size(), 1);
1486 
1487  auto outputs = GetOutputs(graph, layerIndex);
1488  CHECK_VALID_SIZE(outputs.size(), 1);
1489 
1490  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_InstanceNormalizationLayer();
1491  auto fbDescriptor = fbLayer->descriptor();
1492 
1494  descriptor.m_Gamma = fbDescriptor->gamma();
1495  descriptor.m_Beta = fbDescriptor->beta();
1496  descriptor.m_Eps = fbDescriptor->eps();
1497  descriptor.m_DataLayout = ToDataLayout(fbDescriptor->dataLayout());
1498 
1499  const std::string layerName = GetLayerName(graph, layerIndex);
1500  const armnn::TensorInfo outputInfo = ToTensorInfo(outputs[0]);
1501 
1502  IConnectableLayer* layer = m_Network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1503  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1504 
1505  RegisterInputSlots(graph, layerIndex, layer);
1506  RegisterOutputSlots(graph, layerIndex, layer);
1507 }
1508 
1509 void Deserializer::ParseL2Normalization(GraphPtr graph, unsigned int layerIndex)
1510 {
1511  CHECK_LAYERS(graph, 0, layerIndex);
1512 
1513  auto inputs = GetInputs(graph, layerIndex);
1514  CHECK_VALID_SIZE(inputs.size(), 1);
1515 
1516  auto outputs = GetOutputs(graph, layerIndex);
1517  CHECK_VALID_SIZE(outputs.size(), 1);
1518  auto outputInfo = ToTensorInfo(outputs[0]);
1519 
1520  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_L2NormalizationLayer();
1521  auto flatBufferDescriptor = flatBufferLayer->descriptor();
1522 
1523  auto layerName = GetLayerName(graph, layerIndex);
1525  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
1526  descriptor.m_Eps = flatBufferDescriptor->eps();
1527 
1528  IConnectableLayer* layer = m_Network->AddL2NormalizationLayer(descriptor, layerName.c_str());
1529  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1530 
1531  RegisterInputSlots(graph, layerIndex, layer);
1532  RegisterOutputSlots(graph, layerIndex, layer);
1533 }
1534 
1535 void Deserializer::ParseLogicalBinary(GraphPtr graph, unsigned int layerIndex)
1536 {
1537  CHECK_LAYERS(graph, 0, layerIndex);
1538  CHECK_LOCATION();
1539 
1540  auto inputs = GetInputs(graph, layerIndex);
1541  CHECK_VALID_SIZE(inputs.size(), 2);
1542 
1543  auto outputs = GetOutputs(graph, layerIndex);
1544  CHECK_VALID_SIZE(outputs.size(), 1);
1545 
1546  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_LogicalBinaryLayer();
1547  auto fbDescriptor = fbLayer->descriptor();
1548 
1549  armnn::LogicalBinaryDescriptor descriptor;
1550  descriptor.m_Operation = ToLogicalBinaryOperation(fbDescriptor->operation());
1551 
1552  const std::string& layerName = GetLayerName(graph, layerIndex);
1553  IConnectableLayer* layer = m_Network->AddLogicalBinaryLayer(descriptor, layerName.c_str());
1554 
1555  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1556  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1557 
1558  RegisterInputSlots(graph, layerIndex, layer);
1559  RegisterOutputSlots(graph, layerIndex, layer);
1560 }
1561 
1562 void Deserializer::ParseLogSoftmax(GraphPtr graph, unsigned int layerIndex)
1563 {
1564  CHECK_LAYERS(graph, 0, layerIndex);
1565 
1566  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
1567  CHECK_VALID_SIZE(inputs.size(), 1);
1568 
1569  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
1570  CHECK_VALID_SIZE(outputs.size(), 1);
1571 
1572  armnn::LogSoftmaxDescriptor descriptor;
1573  descriptor.m_Beta = graph->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->descriptor()->beta();
1574  descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_LogSoftmaxLayer()->descriptor()->axis();
1575  auto layerName = GetLayerName(graph, layerIndex);
1576 
1577  IConnectableLayer* layer = m_Network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
1578 
1579  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1580  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1581 
1582  RegisterInputSlots(graph, layerIndex, layer);
1583  RegisterOutputSlots(graph, layerIndex, layer);
1584 }
1585 
1586 void Deserializer::ParseMinimum(GraphPtr graph, unsigned int layerIndex)
1587 {
1588  CHECK_LAYERS(graph, 0, layerIndex);
1589  auto inputs = GetInputs(graph, layerIndex);
1590  CHECK_LOCATION();
1591  CHECK_VALID_SIZE(inputs.size(), 2);
1592 
1593  auto outputs = GetOutputs(graph, layerIndex);
1594  CHECK_VALID_SIZE(outputs.size(), 1);
1595 
1596  auto layerName = GetLayerName(graph, layerIndex);
1597  IConnectableLayer* layer = m_Network->AddMinimumLayer(layerName.c_str());
1598 
1599  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1600  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1601 
1602  RegisterInputSlots(graph, layerIndex, layer);
1603  RegisterOutputSlots(graph, layerIndex, layer);
1604 }
1605 
1606 void Deserializer::ParseMaximum(GraphPtr graph, unsigned int layerIndex)
1607 {
1608  CHECK_LAYERS(graph, 0, layerIndex);
1609  auto inputs = GetInputs(graph, layerIndex);
1610  CHECK_LOCATION();
1611  CHECK_VALID_SIZE(inputs.size(), 2);
1612 
1613  auto outputs = GetOutputs(graph, layerIndex);
1614  CHECK_VALID_SIZE(outputs.size(), 1);
1615 
1616  auto layerName = GetLayerName(graph, layerIndex);
1617  IConnectableLayer* layer = m_Network->AddMaximumLayer(layerName.c_str());
1618 
1619  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1620  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1621 
1622  RegisterInputSlots(graph, layerIndex, layer);
1623  RegisterOutputSlots(graph, layerIndex, layer);
1624 }
1625 
1626 const armnnSerializer::OriginsDescriptor* GetOriginsDescriptor(const armnnSerializer::SerializedGraph* graph,
1627  unsigned int layerIndex)
1628 {
1629  auto layerType = graph->layers()->Get(layerIndex)->layer_type();
1630 
1631  switch (layerType)
1632  {
1633  case Layer::Layer_ConcatLayer:
1634  return graph->layers()->Get(layerIndex)->layer_as_ConcatLayer()->descriptor();
1635  case Layer::Layer_MergerLayer:
1636  return graph->layers()->Get(layerIndex)->layer_as_MergerLayer()->descriptor();
1637  default:
1638  throw armnn::Exception("unknown layer type, should be concat or merger");
1639  }
1640 }
1641 
1642 void Deserializer::ParseComparison(GraphPtr graph, unsigned int layerIndex)
1643 {
1644  CHECK_LAYERS(graph, 0, layerIndex);
1645  CHECK_LOCATION();
1646 
1647  auto inputs = GetInputs(graph, layerIndex);
1648  CHECK_VALID_SIZE(inputs.size(), 2);
1649 
1650  auto outputs = GetOutputs(graph, layerIndex);
1651  CHECK_VALID_SIZE(outputs.size(), 1);
1652 
1653  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ComparisonLayer();
1654  auto fbDescriptor = fbLayer->descriptor();
1655 
1656  armnn::ComparisonDescriptor descriptor;
1657  descriptor.m_Operation = ToComparisonOperation(fbDescriptor->operation());
1658 
1659  const std::string& layerName = GetLayerName(graph, layerIndex);
1660  IConnectableLayer* layer = m_Network->AddComparisonLayer(descriptor, layerName.c_str());
1661 
1662  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1663  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1664 
1665  RegisterInputSlots(graph, layerIndex, layer);
1666  RegisterOutputSlots(graph, layerIndex, layer);
1667 }
1668 
1669 void Deserializer::ParseElementwiseUnary(GraphPtr graph, unsigned int layerIndex)
1670 {
1671  CHECK_LAYERS(graph, 0, layerIndex);
1672  CHECK_LOCATION();
1673 
1674  auto inputs = GetInputs(graph, layerIndex);
1675  CHECK_VALID_SIZE(inputs.size(), 1);
1676 
1677  auto outputs = GetOutputs(graph, layerIndex);
1678  CHECK_VALID_SIZE(outputs.size(), 1);
1679 
1680  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_ElementwiseUnaryLayer();
1681  auto fbDescriptor = fbLayer->descriptor();
1682 
1684  descriptor.m_Operation = ToUnaryOperation(fbDescriptor->operation());
1685 
1686  const std::string& layerName = GetLayerName(graph, layerIndex);
1687  IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
1688 
1689  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1690  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1691 
1692  RegisterInputSlots(graph, layerIndex, layer);
1693  RegisterOutputSlots(graph, layerIndex, layer);
1694 }
1695 
1696 void Deserializer::ParseConcat(GraphPtr graph, unsigned int layerIndex)
1697 {
1698  CHECK_LAYERS(graph, 0, layerIndex);
1699  CHECK_LOCATION();
1700 
1701  auto outputs = GetOutputs(graph, layerIndex);
1702  CHECK_VALID_SIZE(outputs.size(), 1);
1703 
1704  auto layerName = GetLayerName(graph, layerIndex);
1705  auto originsDescriptor = GetOriginsDescriptor(graph, layerIndex);
1706  unsigned int numViews = originsDescriptor->numViews();
1707  unsigned int numDimensions = originsDescriptor->numDimensions();
1708 
1709  // can now check the number of inputs == number of views
1710  auto inputs = GetInputs(graph, layerIndex);
1711  CHECK_VALID_SIZE(inputs.size(), numViews);
1712 
1713  armnn::OriginsDescriptor descriptor(numViews, numDimensions);
1714  auto originsPtr = originsDescriptor->viewOrigins();
1715  for (unsigned int v = 0; v < numViews; ++v)
1716  {
1717  auto originPtr = originsPtr->Get(v);
1718  for (unsigned int d = 0; d < numDimensions; ++d)
1719  {
1720  uint32_t value = originPtr->data()->Get(d);
1721  descriptor.SetViewOriginCoord(v, d, value);
1722  }
1723  }
1724  descriptor.SetConcatAxis(originsDescriptor->concatAxis());
1725 
1726  IConnectableLayer* layer = m_Network->AddConcatLayer(descriptor, layerName.c_str());
1727  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1728  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1729 
1730  RegisterInputSlots(graph, layerIndex, layer);
1731  RegisterOutputSlots(graph, layerIndex, layer);
1732 }
1733 
1734 void Deserializer::ParseMultiplication(GraphPtr graph, unsigned int layerIndex)
1735 {
1736  CHECK_LAYERS(graph, 0, layerIndex);
1737  auto inputs = GetInputs(graph, layerIndex);
1738  CHECK_LOCATION();
1739  CHECK_VALID_SIZE(inputs.size(), 2);
1740 
1741  auto outputs = GetOutputs(graph, layerIndex);
1742  CHECK_VALID_SIZE(outputs.size(), 1);
1743 
1744  auto layerName = GetLayerName(graph, layerIndex);
1745  IConnectableLayer* layer = m_Network->AddMultiplicationLayer(layerName.c_str());
1746 
1747  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1748  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1749 
1750  RegisterInputSlots(graph, layerIndex, layer);
1751  RegisterOutputSlots(graph, layerIndex, layer);
1752 }
1753 
1754 void Deserializer::ParseFloor(GraphPtr graph, unsigned int layerIndex)
1755 {
1756  CHECK_LAYERS(graph, 0, layerIndex);
1757  CHECK_LOCATION();
1758 
1759  auto inputs = GetInputs(graph, layerIndex);
1760  CHECK_VALID_SIZE(inputs.size(), 1);
1761 
1762  auto outputs = GetOutputs(graph, layerIndex);
1763  CHECK_VALID_SIZE(outputs.size(), 1);
1764 
1765  auto layerName = GetLayerName(graph, layerIndex);
1766 
1767  armnn::IConnectableLayer* layer;
1768 
1769  layer = m_Network->AddFloorLayer(layerName.c_str());
1770 
1771  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1772  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1773 
1774  RegisterInputSlots(graph, layerIndex, layer);
1775  RegisterOutputSlots(graph, layerIndex, layer);
1776 }
1777 
1778 void Deserializer::ParseFullyConnected(GraphPtr graph, unsigned int layerIndex)
1779 {
1780  CHECK_LAYERS(graph, 0, layerIndex);
1781  auto inputs = GetInputs(graph, layerIndex);
1782  CHECK_LOCATION();
1783  CHECK_VALID_SIZE(inputs.size(), 1);
1784 
1785  auto outputs = GetOutputs(graph, layerIndex);
1786  CHECK_VALID_SIZE(outputs.size(), 1);
1787 
1788  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_FullyConnectedLayer();
1789  auto layerName = GetLayerName(graph, layerIndex);
1790  auto flatBufferDescriptor = flatBufferLayer->descriptor();
1791 
1792  armnn::FullyConnectedDescriptor fullyConnectedDescriptor;
1793  fullyConnectedDescriptor.m_BiasEnabled = flatBufferDescriptor->biasEnabled();
1794  fullyConnectedDescriptor.m_TransposeWeightMatrix = flatBufferDescriptor->transposeWeightsMatrix();
1795 
1796  armnn::ConstTensor weightsTensor = ToConstTensor(flatBufferLayer->weights());
1797 
1798  armnn::IConnectableLayer* layer;
1800  if (flatBufferDescriptor->biasEnabled())
1801  {
1802  armnn::ConstTensor biasTensorData = ToConstTensor(flatBufferLayer->biases());
1803  optionalBiases = armnn::Optional<armnn::ConstTensor>(biasTensorData);
1804  }
1805  layer = m_Network->AddFullyConnectedLayer(fullyConnectedDescriptor,
1806  weightsTensor,
1807  optionalBiases,
1808  layerName.c_str());
1809 
1810  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1811  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1812 
1813  RegisterInputSlots(graph, layerIndex, layer);
1814  RegisterOutputSlots(graph, layerIndex, layer);
1815 }
1816 
1817 void Deserializer::ParsePad(GraphPtr graph, unsigned int layerIndex)
1818 {
1819  CHECK_LAYERS(graph, 0, layerIndex);
1820 
1821  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
1822  CHECK_VALID_SIZE(inputs.size(), 1);
1823 
1824  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
1825  CHECK_VALID_SIZE(outputs.size(), 1);
1826 
1827  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_PadLayer()->descriptor();
1828  auto flatBufferPadList = flatBufferDescriptor->padList();
1829  float padValue = flatBufferDescriptor->padValue();
1830 
1831  if (flatBufferPadList->Length() % 2 != 0)
1832  {
1833  throw ParseException(fmt::format("The size of the pad list must be divisible by 2 {}",
1834  CHECK_LOCATION().AsString()));
1835  }
1836 
1837  std::vector<std::pair<unsigned int, unsigned int>> padList;
1838  padList.reserve(flatBufferPadList->Length() / 2);
1839  for (unsigned int i = 0; i < flatBufferPadList->Length() - 1; i += 2)
1840  {
1841  padList.emplace_back(flatBufferPadList->Get(i), flatBufferPadList->Get(i+1));
1842  }
1843 
1844  armnn::PadDescriptor descriptor(padList, padValue);
1845 
1846  auto layerName = GetLayerName(graph, layerIndex);
1847  IConnectableLayer* layer = m_Network->AddPadLayer(descriptor, layerName.c_str());
1848 
1849  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
1850  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1851 
1852  RegisterInputSlots(graph, layerIndex, layer);
1853  RegisterOutputSlots(graph, layerIndex, layer);
1854 }
1855 
1856 void Deserializer::ParsePermute(GraphPtr graph, unsigned int layerIndex)
1857 {
1858  CHECK_LAYERS(graph, 0, layerIndex);
1859 
1860  auto dimsMapping =
1861  graph->layers()->Get(layerIndex)->layer_as_PermuteLayer()->descriptor()->dimMappings();
1862 
1863  auto inputs = GetInputs(graph, layerIndex);
1864  CHECK_VALID_SIZE(inputs.size(), 1);
1865 
1866  auto outputs = GetOutputs(graph, layerIndex);
1867  CHECK_VALID_SIZE(outputs.size(), 1);
1868  auto outputInfo = ToTensorInfo(outputs[0]);
1869 
1870  auto layerName = GetLayerName(graph, layerIndex);
1871  const armnn::PermuteDescriptor descriptor(armnn::PermutationVector(dimsMapping->data(), dimsMapping->Length()));
1872 
1873  IConnectableLayer* layer = m_Network->AddPermuteLayer(descriptor, layerName.c_str());
1874  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1875 
1876  RegisterInputSlots(graph, layerIndex, layer);
1877  RegisterOutputSlots(graph, layerIndex, layer);
1878 }
1879 
1881  unsigned int layerIndex)
1882 {
1883  IgnoreUnused(layerIndex);
1885 
1886  switch (pooling2dDesc->poolType())
1887  {
1888  case PoolingAlgorithm_Average:
1889  {
1891  break;
1892  }
1893  case PoolingAlgorithm_Max:
1894  {
1896  break;
1897  }
1898  default:
1899  {
1900  ARMNN_ASSERT_MSG(false, "Unsupported pooling algorithm");
1901  }
1902  }
1903 
1904  switch (pooling2dDesc->outputShapeRounding())
1905  {
1906  case OutputShapeRounding_Floor:
1907  {
1909  break;
1910  }
1911  case OutputShapeRounding_Ceiling:
1912  {
1914  break;
1915  }
1916  default:
1917  {
1918  ARMNN_ASSERT_MSG(false, "Unsupported output shape rounding");
1919  }
1920  }
1921 
1922  switch (pooling2dDesc->paddingMethod())
1923  {
1924  case PaddingMethod_Exclude:
1925  {
1927  break;
1928  }
1929  case PaddingMethod_IgnoreValue:
1930  {
1932  break;
1933  }
1934  default:
1935  {
1936  ARMNN_ASSERT_MSG(false, "Unsupported padding method");
1937  }
1938  }
1939 
1940  switch (pooling2dDesc->dataLayout())
1941  {
1942  case DataLayout_NCHW:
1943  {
1945  break;
1946  }
1947  case DataLayout_NHWC:
1948  {
1950  break;
1951  }
1952  default:
1953  {
1954  ARMNN_ASSERT_MSG(false, "Unsupported data layout");
1955  }
1956  }
1957 
1958  desc.m_PadRight = pooling2dDesc->padRight();
1959  desc.m_PadLeft = pooling2dDesc->padLeft();
1960  desc.m_PadBottom = pooling2dDesc->padBottom();
1961  desc.m_PadTop = pooling2dDesc->padTop();
1962  desc.m_StrideX = pooling2dDesc->strideX();
1963  desc.m_StrideY = pooling2dDesc->strideY();
1964  desc.m_PoolWidth = pooling2dDesc->poolWidth();
1965  desc.m_PoolHeight = pooling2dDesc->poolHeight();
1966 
1967  return desc;
1968 }
1969 
1970 void Deserializer::ParsePooling2d(GraphPtr graph, unsigned int layerIndex)
1971 {
1972  CHECK_LAYERS(graph, 0, layerIndex);
1973 
1974  auto pooling2dDes = graph->layers()->Get(layerIndex)->layer_as_Pooling2dLayer()->descriptor();
1975  auto inputs = GetInputs(graph, layerIndex);
1976  CHECK_VALID_SIZE(inputs.size(), 1);
1977 
1978  auto outputs = GetOutputs(graph, layerIndex);
1979  CHECK_VALID_SIZE(outputs.size(), 1);
1980  auto outputInfo = ToTensorInfo(outputs[0]);
1981 
1982  auto pooling2dDescriptor = GetPoolingDescriptor(pooling2dDes, layerIndex);
1983  auto layerName = GetLayerName(graph, layerIndex);
1984  IConnectableLayer* layer = m_Network->AddPooling2dLayer(pooling2dDescriptor, layerName.c_str());
1985  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1986 
1987  RegisterInputSlots(graph, layerIndex, layer);
1988  RegisterOutputSlots(graph, layerIndex, layer);
1989 }
1990 
1991 void Deserializer::ParseQuantize(GraphPtr graph, unsigned int layerIndex)
1992 {
1993  CHECK_LAYERS(graph, 0, layerIndex);
1994 
1995  auto inputs = GetInputs(graph, layerIndex);
1996  CHECK_VALID_SIZE(inputs.size(), 1);
1997 
1998  auto outputs = GetOutputs(graph, layerIndex);
1999  CHECK_VALID_SIZE(outputs.size(), 1);
2000  auto outputInfo = ToTensorInfo(outputs[0]);
2001 
2002  auto layerName = GetLayerName(graph, layerIndex);
2003  IConnectableLayer* layer = m_Network->AddQuantizeLayer(layerName.c_str());
2004  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2005 
2006  RegisterInputSlots(graph, layerIndex, layer);
2007  RegisterOutputSlots(graph, layerIndex, layer);
2008 }
2009 
2011  const std::vector<uint32_t>& targetDimsIn)
2012 {
2013  std::vector<unsigned int> outputDims(targetDimsIn.begin(), targetDimsIn.end());
2014  const auto stretchDim = std::find(targetDimsIn.begin(), targetDimsIn.end(), -1);
2015 
2016  if (stretchDim != targetDimsIn.end())
2017  {
2018  if (std::find(std::next(stretchDim), targetDimsIn.end(), -1) != targetDimsIn.end())
2019  {
2020  throw ParseException(fmt::format("At most one component of shape can be -1 {}",
2021  CHECK_LOCATION().AsString()));
2022  }
2023 
2024  auto targetNumElements =
2025  armnn::numeric_cast<unsigned int>(
2026  std::accumulate(targetDimsIn.begin(), targetDimsIn.end(), -1, std::multiplies<int32_t>()));
2027 
2028  auto stretchIndex = static_cast<size_t>(std::distance(targetDimsIn.begin(), stretchDim));
2029  outputDims[stretchIndex] = inputTensorInfo.GetNumElements() / targetNumElements;
2030  }
2031 
2032  TensorShape outputShape = TensorShape(static_cast<unsigned int>(outputDims.size()), outputDims.data());
2033 
2034  armnn::TensorInfo reshapeInfo = inputTensorInfo;
2035  reshapeInfo.SetShape(outputShape);
2036 
2037  return reshapeInfo;
2038 }
2039 
2040 void Deserializer::ParseRank(GraphPtr graph, unsigned int layerIndex)
2041 {
2042  CHECK_LAYERS(graph, 0, layerIndex);
2043 
2044  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2045  CHECK_VALID_SIZE(inputs.size(), 1);
2046 
2047  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2048  CHECK_VALID_SIZE(outputs.size(), 1);
2049 
2050  auto layerName = GetLayerName(graph, layerIndex);
2051  IConnectableLayer* layer = m_Network->AddRankLayer( layerName.c_str());
2052 
2053  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2054  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2055 
2056  RegisterInputSlots(graph, layerIndex, layer);
2057  RegisterOutputSlots(graph, layerIndex, layer);
2058 }
2059 
2060 void Deserializer::ParseReshape(GraphPtr graph, unsigned int layerIndex)
2061 {
2062  CHECK_LAYERS(graph, 0, layerIndex);
2063  auto inputs = GetInputs(graph, layerIndex);
2064 
2065  auto outputs = GetOutputs(graph, layerIndex);
2066  CHECK_VALID_SIZE(outputs.size(), 1);
2067 
2068  armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
2069  armnn::TensorInfo actualOutputTensorInfo = ToTensorInfo(outputs[0]);
2070 
2071  const auto targetDims = graph->layers()->Get(layerIndex)->layer_as_ReshapeLayer()->descriptor()->targetShape();
2072  std::vector<uint32_t> outputDims(targetDims->begin(), targetDims->begin() + targetDims->size());
2073 
2074  armnn::TensorInfo reshapeOutputTensorInfo = Deserializer::OutputShapeOfReshape(inputTensorInfo, outputDims);
2075  const armnn::TensorShape& reshapeOutputTensorShape = reshapeOutputTensorInfo.GetShape();
2076 
2077  const std::vector<uint32_t> expectedDims(outputs[0]->dimensions()->begin(),
2078  outputs[0]->dimensions()->begin() + outputs[0]->dimensions()->size());
2079 
2080  if (inputs.size() > 1 && !CheckShape(reshapeOutputTensorShape, expectedDims))
2081  {
2082  std::stringstream ss;
2083  ss << "New shape defined in reshape parameters "
2084  << reshapeOutputTensorShape
2085  << " does not equal output shape "
2086  << actualOutputTensorInfo.GetShape()
2087  << ": "
2088  << CHECK_LOCATION().AsString();
2089  throw ParseException(ss.str());
2090  }
2091 
2092  armnn::ReshapeDescriptor reshapeDesc;
2093  reshapeDesc.m_TargetShape = reshapeOutputTensorShape;
2094 
2095  auto layerName = GetLayerName(graph, layerIndex);
2096  IConnectableLayer* layer = m_Network->AddReshapeLayer(reshapeDesc, layerName.c_str());
2097  layer->GetOutputSlot(0).SetTensorInfo(reshapeOutputTensorInfo);
2098 
2099  RegisterInputSlots(graph, layerIndex, layer);
2100  RegisterOutputSlots(graph, layerIndex, layer);
2101 }
2102 
2103 void Deserializer::ParseResize(GraphPtr graph, unsigned int layerIndex)
2104 {
2105  CHECK_LAYERS(graph, 0, layerIndex);
2106 
2107  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2108  CHECK_VALID_SIZE(inputs.size(), 1);
2109 
2110  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2111  CHECK_VALID_SIZE(outputs.size(), 1);
2112 
2113  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_ResizeLayer()->descriptor();
2114 
2115  armnn::ResizeDescriptor descriptor;
2116  descriptor.m_TargetWidth = flatBufferDescriptor->targetWidth();
2117  descriptor.m_TargetHeight = flatBufferDescriptor->targetHeight();
2118  descriptor.m_Method = ToResizeMethod(flatBufferDescriptor->method());
2119  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2120  descriptor.m_AlignCorners = flatBufferDescriptor->alignCorners();
2121  descriptor.m_HalfPixelCenters = flatBufferDescriptor->halfPixelCenters();
2122 
2123  auto layerName = GetLayerName(graph, layerIndex);
2124  IConnectableLayer* layer = m_Network->AddResizeLayer(descriptor, layerName.c_str());
2125 
2126  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2127  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2128 
2129  RegisterInputSlots(graph, layerIndex, layer);
2130  RegisterOutputSlots(graph, layerIndex, layer);
2131 }
2132 
2133 void Deserializer::ParseResizeBilinear(GraphPtr graph, unsigned int layerIndex)
2134 {
2135  CHECK_LAYERS(graph, 0, layerIndex);
2136 
2137  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2138  CHECK_VALID_SIZE(inputs.size(), 1);
2139 
2140  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2141  CHECK_VALID_SIZE(outputs.size(), 1);
2142 
2143  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_ResizeBilinearLayer()->descriptor();
2144 
2145  armnn::ResizeDescriptor descriptor;
2146  descriptor.m_TargetWidth = flatBufferDescriptor->targetWidth();
2147  descriptor.m_TargetHeight = flatBufferDescriptor->targetHeight();
2149  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2150  descriptor.m_AlignCorners = flatBufferDescriptor->alignCorners();
2151  descriptor.m_HalfPixelCenters = flatBufferDescriptor->halfPixelCenters();
2152 
2153  auto layerName = GetLayerName(graph, layerIndex);
2154  IConnectableLayer* layer = m_Network->AddResizeLayer(descriptor, layerName.c_str());
2155 
2156  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2157  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2158 
2159  RegisterInputSlots(graph, layerIndex, layer);
2160  RegisterOutputSlots(graph, layerIndex, layer);
2161 }
2162 
2163 void Deserializer::ParseSoftmax(GraphPtr graph, unsigned int layerIndex)
2164 {
2165  CHECK_LAYERS(graph, 0, layerIndex);
2166 
2167  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2168  CHECK_VALID_SIZE(inputs.size(), 1);
2169 
2170  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2171  CHECK_VALID_SIZE(outputs.size(), 1);
2172 
2173  armnn::SoftmaxDescriptor descriptor;
2174  descriptor.m_Beta = graph->layers()->Get(layerIndex)->layer_as_SoftmaxLayer()->descriptor()->beta();
2175  auto layerName = GetLayerName(graph, layerIndex);
2176 
2177  IConnectableLayer* layer = m_Network->AddSoftmaxLayer(descriptor, layerName.c_str());
2178 
2179  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2180  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2181 
2182  RegisterInputSlots(graph, layerIndex, layer);
2183  RegisterOutputSlots(graph, layerIndex, layer);
2184 }
2185 
2186 void Deserializer::ParseSpaceToBatchNd(GraphPtr graph, unsigned int layerIndex)
2187 {
2188  CHECK_LAYERS(graph, 0, layerIndex);
2189 
2190  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2191  CHECK_VALID_SIZE(inputs.size(), 1);
2192 
2193  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2194  CHECK_VALID_SIZE(outputs.size(), 1);
2195 
2196  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_SpaceToBatchNdLayer()->descriptor();
2197  auto flatBufferPadList = flatBufferDescriptor->padList();
2198  auto flatBufferBlockShape = flatBufferDescriptor->blockShape();
2199 
2200  if (flatBufferPadList->Length() % 2 != 0)
2201  {
2202  throw ParseException(fmt::format("The size of the pad list must be divisible by 2 {}",
2203  CHECK_LOCATION().AsString()));
2204  }
2205 
2206  std::vector<std::pair<unsigned int, unsigned int>> padList;
2207  padList.reserve(flatBufferPadList->Length() / 2);
2208  for (unsigned int i = 0; i < flatBufferPadList->Length() - 1; i += 2)
2209  {
2210  padList.emplace_back(flatBufferPadList->Get(i), flatBufferPadList->Get(i+1));
2211  }
2212 
2214  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2215  descriptor.m_BlockShape =
2216  std::vector<unsigned int>(flatBufferBlockShape->begin(), flatBufferBlockShape->end());
2217  descriptor.m_PadList = padList;
2218 
2219  auto layerName = GetLayerName(graph, layerIndex);
2220  IConnectableLayer* layer = m_Network->AddSpaceToBatchNdLayer(descriptor, layerName.c_str());
2221 
2222  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2223  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2224 
2225  RegisterInputSlots(graph, layerIndex, layer);
2226  RegisterOutputSlots(graph, layerIndex, layer);
2227 }
2228 
2229 void Deserializer::ParseSpaceToDepth(GraphPtr graph, unsigned int layerIndex)
2230 {
2231  CHECK_LAYERS(graph, 0, layerIndex);
2232 
2233  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2234  CHECK_VALID_SIZE(inputs.size(), 1);
2235 
2236  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2237  CHECK_VALID_SIZE(outputs.size(), 1);
2238 
2239  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_SpaceToDepthLayer()->descriptor();
2240 
2241  armnn::SpaceToDepthDescriptor descriptor;
2242  descriptor.m_BlockSize = flatBufferDescriptor->blockSize();
2243  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2244 
2245  auto layerName = GetLayerName(graph, layerIndex);
2246  IConnectableLayer* layer = m_Network->AddSpaceToDepthLayer(descriptor, layerName.c_str());
2247 
2248  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2249  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2250 
2251  RegisterInputSlots(graph, layerIndex, layer);
2252  RegisterOutputSlots(graph, layerIndex, layer);
2253 }
2254 
2256  Deserializer::NormalizationDescriptorPtr normalizationDescriptor,
2257  unsigned int layerIndex)
2258 {
2259  IgnoreUnused(layerIndex);
2261 
2262  switch (normalizationDescriptor->normChannelType())
2263  {
2264  case NormalizationAlgorithmChannel_Across:
2265  {
2267  break;
2268  }
2269  case NormalizationAlgorithmChannel_Within:
2270  {
2272  break;
2273  }
2274  default:
2275  {
2276  ARMNN_ASSERT_MSG(false, "Unsupported normalization channel type");
2277  }
2278  }
2279 
2280  switch (normalizationDescriptor->normMethodType())
2281  {
2282  case NormalizationAlgorithmMethod_LocalBrightness:
2283  {
2285  break;
2286  }
2287  case NormalizationAlgorithmMethod_LocalContrast:
2288  {
2290  break;
2291  }
2292  default:
2293  {
2294  ARMNN_ASSERT_MSG(false, "Unsupported normalization method type");
2295  }
2296  }
2297 
2298  switch (normalizationDescriptor->dataLayout())
2299  {
2300  case DataLayout_NCHW:
2301  {
2303  break;
2304  }
2305  case DataLayout_NHWC:
2306  {
2308  break;
2309  }
2310  default:
2311  {
2312  ARMNN_ASSERT_MSG(false, "Unsupported data layout");
2313  }
2314  }
2315 
2316  desc.m_Alpha = normalizationDescriptor->alpha();
2317  desc.m_Beta = normalizationDescriptor->beta();
2318  desc.m_K = normalizationDescriptor->k();
2319  desc.m_NormSize = normalizationDescriptor->normSize();
2320 
2321  return desc;
2322 }
2323 
2324 void Deserializer::ParseNormalization(GraphPtr graph, unsigned int layerIndex)
2325 {
2326  CHECK_LAYERS(graph, 0, layerIndex);
2327 
2328  auto normalizationDes = graph->layers()->Get(layerIndex)->layer_as_NormalizationLayer()->descriptor();
2329 
2330  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2331  CHECK_VALID_SIZE(inputs.size(), 1);
2332 
2333  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2334  CHECK_VALID_SIZE(outputs.size(), 1);
2335 
2336  auto outputInfo = ToTensorInfo(outputs[0]);
2337 
2338  auto normalizationDescriptor = GetNormalizationDescriptor(normalizationDes, layerIndex);
2339  auto layerName = GetLayerName(graph, layerIndex);
2340 
2341  IConnectableLayer* layer = m_Network->AddNormalizationLayer(normalizationDescriptor, layerName.c_str());
2342  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2343 
2344  RegisterInputSlots(graph, layerIndex, layer);
2345  RegisterOutputSlots(graph, layerIndex, layer);
2346 }
2347 
2348 void Deserializer::ParseRsqrt(GraphPtr graph, unsigned int layerIndex)
2349 {
2350  CHECK_LAYERS(graph, 0, layerIndex);
2351  auto inputs = GetInputs(graph, layerIndex);
2352  CHECK_LOCATION();
2353  CHECK_VALID_SIZE(inputs.size(), 1);
2354 
2355  auto outputs = GetOutputs(graph, layerIndex);
2356  CHECK_VALID_SIZE(outputs.size(), 1);
2357 
2358  auto layerName = GetLayerName(graph, layerIndex);
2359 
2361  IConnectableLayer* layer = m_Network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
2362  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2363  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2364 
2365  RegisterInputSlots(graph, layerIndex, layer);
2366  RegisterOutputSlots(graph, layerIndex, layer);
2367 }
2368 
2369 void Deserializer::ParseSlice(GraphPtr graph, unsigned int layerIndex)
2370 {
2371  CHECK_LAYERS(graph, 0, layerIndex);
2372 
2373  auto inputs = GetInputs(graph, layerIndex);
2374  CHECK_VALID_SIZE(inputs.size(), 1);
2375 
2376  auto outputs = GetOutputs(graph, layerIndex);
2377  CHECK_VALID_SIZE(outputs.size(), 1);
2378 
2379  auto fbDescriptor = graph->layers()->Get(layerIndex)->layer_as_SliceLayer()->descriptor();
2380 
2381  auto fbBegin = fbDescriptor->begin();
2382  auto fbSize = fbDescriptor->size();
2383 
2384  if (fbBegin->Length() != fbSize->Length())
2385  {
2386  throw ParseException(fmt::format("Begin and size descriptors must have the same length {}",
2387  CHECK_LOCATION().AsString()));
2388  }
2389 
2390  armnn::SliceDescriptor descriptor;
2391  descriptor.m_Begin.insert(descriptor.m_Begin.end(), fbBegin->begin(), fbBegin->end());
2392  descriptor.m_Size.insert(descriptor.m_Size.end(), fbSize->begin(), fbSize->end());
2393 
2394  auto layerName = GetLayerName(graph, layerIndex);
2395  IConnectableLayer* layer = m_Network->AddSliceLayer(descriptor, layerName.c_str());
2396 
2397  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2398  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2399 
2400  RegisterInputSlots(graph, layerIndex, layer);
2401  RegisterOutputSlots(graph, layerIndex, layer);
2402 }
2403 
2404 void Deserializer::ParseStridedSlice(GraphPtr graph, unsigned int layerIndex)
2405 {
2406  CHECK_LAYERS(graph, 0, layerIndex);
2407 
2408  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2409  CHECK_VALID_SIZE(inputs.size(), 1);
2410 
2411  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2412  CHECK_VALID_SIZE(outputs.size(), 1);
2413 
2414  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_StridedSliceLayer()->descriptor();
2415 
2416  auto flatBufferBegin = flatBufferDescriptor->begin();
2417  auto flatBufferEnd = flatBufferDescriptor->end();
2418  auto flatBufferStride = flatBufferDescriptor->stride();
2419 
2420  if (!(flatBufferBegin->Length() == flatBufferEnd->Length() &&
2421  flatBufferBegin->Length() == flatBufferStride->Length()))
2422  {
2423  throw ParseException(fmt::format("The size of the begin, end, and stride must be equal {}",
2424  CHECK_LOCATION().AsString()));
2425  }
2426 
2427  std::vector<int> begin(flatBufferBegin->begin(), flatBufferBegin->end());
2428  std::vector<int> end(flatBufferEnd->begin(), flatBufferEnd->end());
2429  std::vector<int> stride(flatBufferStride->begin(), flatBufferStride->end());
2430 
2431  armnn::StridedSliceDescriptor descriptor(begin, end, stride);
2432  descriptor.m_BeginMask = flatBufferDescriptor->beginMask();
2433  descriptor.m_EndMask = flatBufferDescriptor->endMask();
2434  descriptor.m_ShrinkAxisMask = flatBufferDescriptor->shrinkAxisMask();
2435  descriptor.m_EllipsisMask = flatBufferDescriptor->ellipsisMask();
2436  descriptor.m_NewAxisMask = flatBufferDescriptor->newAxisMask();
2437  descriptor.m_DataLayout = ToDataLayout(flatBufferDescriptor->dataLayout());
2438 
2439  auto layerName = GetLayerName(graph, layerIndex);
2440  IConnectableLayer* layer = m_Network->AddStridedSliceLayer(descriptor, layerName.c_str());
2441 
2442  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2443  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2444 
2445  RegisterInputSlots(graph, layerIndex, layer);
2446  RegisterOutputSlots(graph, layerIndex, layer);
2447 }
2448 
2449 void Deserializer::ParseSubtraction(GraphPtr graph, unsigned int layerIndex)
2450 {
2451  CHECK_LAYERS(graph, 0, layerIndex);
2452  auto inputs = GetInputs(graph, layerIndex);
2453  CHECK_LOCATION();
2454  CHECK_VALID_SIZE(inputs.size(), 2);
2455 
2456  auto outputs = GetOutputs(graph, layerIndex);
2457  CHECK_VALID_SIZE(outputs.size(), 1);
2458 
2459  auto layerName = GetLayerName(graph, layerIndex);
2460  IConnectableLayer* layer = m_Network->AddSubtractionLayer(layerName.c_str());
2461 
2462  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2463  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2464 
2465  RegisterInputSlots(graph, layerIndex, layer);
2466  RegisterOutputSlots(graph, layerIndex, layer);
2467 }
2468 
2469 void Deserializer::ParseGather(GraphPtr graph, unsigned int layerIndex)
2470 {
2471  CHECK_LAYERS(graph, 0, layerIndex);
2472 
2473  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2474  CHECK_VALID_SIZE(inputs.size(), 2);
2475 
2476  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2477  CHECK_VALID_SIZE(outputs.size(), 1);
2478 
2479  armnn::GatherDescriptor descriptor;
2480  descriptor.m_Axis = graph->layers()->Get(layerIndex)->layer_as_GatherLayer()->descriptor()->axis();
2481 
2482  auto layerName = GetLayerName(graph, layerIndex);
2483  IConnectableLayer* layer = m_Network->AddGatherLayer(descriptor, layerName.c_str());
2484 
2485  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2486  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2487 
2488  RegisterInputSlots(graph, layerIndex, layer);
2489  RegisterOutputSlots(graph, layerIndex, layer);
2490 }
2491 
2492 void Deserializer::ParseMean(GraphPtr graph, unsigned int layerIndex)
2493 {
2494  CHECK_LAYERS(graph, 0, layerIndex);
2495 
2496  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2497  CHECK_VALID_SIZE(inputs.size(), 1);
2498 
2499  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2500  CHECK_VALID_SIZE(outputs.size(), 1);
2501 
2502  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_MeanLayer()->descriptor();
2503  auto flatBufferAxis = flatBufferDescriptor->axis();
2504  auto flatBufferKeepDims = flatBufferDescriptor->keepDims();
2505 
2506  armnn::MeanDescriptor descriptor;
2507  descriptor.m_Axis = std::vector<unsigned int>(flatBufferAxis->begin(), flatBufferAxis->end());
2508  descriptor.m_KeepDims = flatBufferKeepDims;
2509 
2510  auto layerName = GetLayerName(graph, layerIndex);
2511  IConnectableLayer* layer = m_Network->AddMeanLayer(descriptor, layerName.c_str());
2512 
2513  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2514  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2515 
2516  RegisterInputSlots(graph, layerIndex, layer);
2517  RegisterOutputSlots(graph, layerIndex, layer);
2518 }
2519 
2520 void Deserializer::ParseSplitter(GraphPtr graph, unsigned int layerIndex)
2521 {
2522  CHECK_LAYERS(graph, 0, layerIndex);
2523 
2524  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2525  CHECK_VALID_SIZE(inputs.size(), 1);
2526 
2527  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2528 
2529  auto flatBufferViewsDescriptor = graph->layers()->Get(layerIndex)->layer_as_SplitterLayer()->descriptor();
2530  auto flatBufferViewSizes = flatBufferViewsDescriptor->viewSizes();
2531  auto flatBufferOriginsDescriptor = flatBufferViewsDescriptor->origins();
2532  auto flatBufferViewOrigins = flatBufferOriginsDescriptor->viewOrigins();
2533  uint32_t numViews = flatBufferOriginsDescriptor->numViews();
2534  uint32_t numDimensions = flatBufferOriginsDescriptor->numDimensions();
2535 
2536  // Check numViews and numDimensions corresponds to the ones already serialized ...
2537  // numViews == flatBufferViewSizes.size();
2538  // foreach: numDimensions == flatBufferViewSizes[x].size();
2539 
2540  armnn::ViewsDescriptor viewsDescriptor(numViews, numDimensions);
2541  for(unsigned int vIdx = 0; vIdx < numViews; ++vIdx)
2542  {
2543  for (unsigned int dIdx = 0; dIdx < numDimensions; ++dIdx)
2544  {
2545  viewsDescriptor.SetViewSize(vIdx, dIdx, flatBufferViewSizes->Get(vIdx)->data()->Get(dIdx));
2546  viewsDescriptor.SetViewOriginCoord(vIdx, dIdx, flatBufferViewOrigins->Get(vIdx)->data()->Get(dIdx));
2547  }
2548  }
2549 
2550  auto layerName = GetLayerName(graph, layerIndex);
2551  IConnectableLayer* layer = m_Network->AddSplitterLayer(viewsDescriptor, layerName.c_str());
2552 
2553  // I could have as many outputs as views ...
2554  for(unsigned int vIdx = 0; vIdx < numViews; ++vIdx)
2555  {
2556  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[vIdx]);
2557  layer->GetOutputSlot(vIdx).SetTensorInfo(outputTensorInfo);
2558  }
2559 
2560  RegisterInputSlots(graph, layerIndex, layer);
2561  RegisterOutputSlots(graph, layerIndex, layer);
2562 }
2563 
2565 {
2566  armnn::LstmDescriptor desc;
2567 
2568  desc.m_ActivationFunc = lstmDescriptor->activationFunc();
2569  desc.m_ClippingThresCell = lstmDescriptor->clippingThresCell();
2570  desc.m_ClippingThresProj = lstmDescriptor->clippingThresProj();
2571  desc.m_CifgEnabled = lstmDescriptor->cifgEnabled();
2572  desc.m_PeepholeEnabled = lstmDescriptor->peepholeEnabled();
2573  desc.m_ProjectionEnabled = lstmDescriptor->projectionEnabled();
2574  desc.m_LayerNormEnabled = lstmDescriptor->layerNormEnabled();
2575 
2576  return desc;
2577 }
2578 
2579 void Deserializer::ParseLstm(GraphPtr graph, unsigned int layerIndex)
2580 {
2581  CHECK_LAYERS(graph, 0, layerIndex);
2582 
2583  auto inputs = GetInputs(graph, layerIndex);
2584  CHECK_VALID_SIZE(inputs.size(), 3);
2585 
2586  auto outputs = GetOutputs(graph, layerIndex);
2587  CHECK_VALID_SIZE(outputs.size(), 4);
2588 
2589  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_LstmLayer();
2590  auto layerName = GetLayerName(graph, layerIndex);
2591  auto flatBufferDescriptor = flatBufferLayer->descriptor();
2592  auto flatBufferInputParams = flatBufferLayer->inputParams();
2593 
2594  auto lstmDescriptor = GetLstmDescriptor(flatBufferDescriptor);
2595 
2596  armnn::LstmInputParams lstmInputParams;
2597 
2598  armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights());
2599  armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights());
2600  armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights());
2601  armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights());
2602  armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights());
2603  armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights());
2604  armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias());
2605  armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias());
2606  armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias());
2607 
2608  lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights;
2609  lstmInputParams.m_InputToCellWeights = &inputToCellWeights;
2610  lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights;
2611  lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
2612  lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights;
2613  lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
2614  lstmInputParams.m_ForgetGateBias = &forgetGateBias;
2615  lstmInputParams.m_CellBias = &cellBias;
2616  lstmInputParams.m_OutputGateBias = &outputGateBias;
2617 
2618  armnn::ConstTensor inputToInputWeights;
2619  armnn::ConstTensor recurrentToInputWeights;
2620  armnn::ConstTensor cellToInputWeights;
2621  armnn::ConstTensor inputGateBias;
2622  if (!lstmDescriptor.m_CifgEnabled)
2623  {
2624  inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights());
2625  recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights());
2626  cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights());
2627  inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias());
2628 
2629  lstmInputParams.m_InputToInputWeights = &inputToInputWeights;
2630  lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights;
2631  lstmInputParams.m_CellToInputWeights = &cellToInputWeights;
2632  lstmInputParams.m_InputGateBias = &inputGateBias;
2633  }
2634 
2635  armnn::ConstTensor projectionWeights;
2636  armnn::ConstTensor projectionBias;
2637  if (lstmDescriptor.m_ProjectionEnabled)
2638  {
2639  projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights());
2640  projectionBias = ToConstTensor(flatBufferInputParams->projectionBias());
2641 
2642  lstmInputParams.m_ProjectionWeights = &projectionWeights;
2643  lstmInputParams.m_ProjectionBias = &projectionBias;
2644  }
2645 
2646  armnn::ConstTensor cellToForgetWeights;
2647  armnn::ConstTensor cellToOutputWeights;
2648  if (lstmDescriptor.m_PeepholeEnabled)
2649  {
2650  cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights());
2651  cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights());
2652 
2653  lstmInputParams.m_CellToForgetWeights = &cellToForgetWeights;
2654  lstmInputParams.m_CellToOutputWeights = &cellToOutputWeights;
2655  }
2656 
2657  armnn::ConstTensor inputLayerNormWeights;
2658  armnn::ConstTensor forgetLayerNormWeights;
2659  armnn::ConstTensor cellLayerNormWeights;
2660  armnn::ConstTensor outputLayerNormWeights;
2661  if (lstmDescriptor.m_LayerNormEnabled)
2662  {
2663  if (!lstmDescriptor.m_CifgEnabled)
2664  {
2665  inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights());
2666  lstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights;
2667  }
2668  forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights());
2669  cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights());
2670  outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights());
2671 
2672  lstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
2673  lstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights;
2674  lstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights;
2675  }
2676 
2677  IConnectableLayer* layer = m_Network->AddLstmLayer(lstmDescriptor, lstmInputParams, layerName.c_str());
2678 
2679  armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[0]);
2680  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo1);
2681 
2682  armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[1]);
2683  layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo2);
2684 
2685  armnn::TensorInfo outputTensorInfo3 = ToTensorInfo(outputs[2]);
2686  layer->GetOutputSlot(2).SetTensorInfo(outputTensorInfo3);
2687 
2688  armnn::TensorInfo outputTensorInfo4 = ToTensorInfo(outputs[3]);
2689  layer->GetOutputSlot(3).SetTensorInfo(outputTensorInfo4);
2690 
2691  RegisterInputSlots(graph, layerIndex, layer);
2692  RegisterOutputSlots(graph, layerIndex, layer);
2693 }
2694 
2696 {
2698 
2699  desc.m_CifgEnabled = qLstmDescriptor->cifgEnabled();
2700  desc.m_PeepholeEnabled = qLstmDescriptor->peepholeEnabled();
2701  desc.m_ProjectionEnabled = qLstmDescriptor->projectionEnabled();
2702  desc.m_LayerNormEnabled = qLstmDescriptor->layerNormEnabled();
2703 
2704  desc.m_CellClip = qLstmDescriptor->cellClip();
2705  desc.m_ProjectionClip = qLstmDescriptor->projectionClip();
2706 
2707  desc.m_InputIntermediateScale = qLstmDescriptor->inputIntermediateScale();
2708  desc.m_ForgetIntermediateScale = qLstmDescriptor->forgetIntermediateScale();
2709  desc.m_CellIntermediateScale = qLstmDescriptor->cellIntermediateScale();
2710  desc.m_OutputIntermediateScale = qLstmDescriptor->outputIntermediateScale();
2711 
2712  desc.m_HiddenStateScale = qLstmDescriptor->hiddenStateScale();
2713  desc.m_HiddenStateZeroPoint = qLstmDescriptor->hiddenStateZeroPoint();
2714 
2715  return desc;
2716 }
2717 
2718 void Deserializer::ParseQLstm(GraphPtr graph, unsigned int layerIndex)
2719 {
2720  CHECK_LAYERS(graph, 0, layerIndex);
2721 
2722  auto inputs = GetInputs(graph, layerIndex);
2723  CHECK_VALID_SIZE(inputs.size(), 3);
2724 
2725  auto outputs = GetOutputs(graph, layerIndex);
2726  CHECK_VALID_SIZE(outputs.size(), 3);
2727 
2728  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_QLstmLayer();
2729  auto layerName = GetLayerName(graph, layerIndex);
2730  auto flatBufferDescriptor = flatBufferLayer->descriptor();
2731  auto flatBufferInputParams = flatBufferLayer->inputParams();
2732 
2733  auto qLstmDescriptor = GetQLstmDescriptor(flatBufferDescriptor);
2734  armnn::LstmInputParams qLstmInputParams;
2735 
2736  // Mandatory params
2737  armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights());
2738  armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights());
2739  armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights());
2740  armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights());
2741  armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights());
2742  armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights());
2743  armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias());
2744  armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias());
2745  armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias());
2746 
2747  qLstmInputParams.m_InputToForgetWeights = &inputToForgetWeights;
2748  qLstmInputParams.m_InputToCellWeights = &inputToCellWeights;
2749  qLstmInputParams.m_InputToOutputWeights = &inputToOutputWeights;
2750  qLstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
2751  qLstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights;
2752  qLstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
2753  qLstmInputParams.m_ForgetGateBias = &forgetGateBias;
2754  qLstmInputParams.m_CellBias = &cellBias;
2755  qLstmInputParams.m_OutputGateBias = &outputGateBias;
2756 
2757  // Optional CIFG params
2758  armnn::ConstTensor inputToInputWeights;
2759  armnn::ConstTensor recurrentToInputWeights;
2760  armnn::ConstTensor inputGateBias;
2761 
2762  if (!qLstmDescriptor.m_CifgEnabled)
2763  {
2764  inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights());
2765  recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights());
2766  inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias());
2767 
2768  qLstmInputParams.m_InputToInputWeights = &inputToInputWeights;
2769  qLstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights;
2770  qLstmInputParams.m_InputGateBias = &inputGateBias;
2771  }
2772 
2773  // Optional projection params
2774  armnn::ConstTensor projectionWeights;
2775  armnn::ConstTensor projectionBias;
2776 
2777  if (qLstmDescriptor.m_ProjectionEnabled)
2778  {
2779  projectionWeights = ToConstTensor(flatBufferInputParams->projectionWeights());
2780  projectionBias = ToConstTensor(flatBufferInputParams->projectionBias());
2781 
2782  qLstmInputParams.m_ProjectionWeights = &projectionWeights;
2783  qLstmInputParams.m_ProjectionBias = &projectionBias;
2784  }
2785 
2786  // Optional peephole params
2787  armnn::ConstTensor cellToInputWeights;
2788  armnn::ConstTensor cellToForgetWeights;
2789  armnn::ConstTensor cellToOutputWeights;
2790 
2791  if (qLstmDescriptor.m_PeepholeEnabled)
2792  {
2793  if (!qLstmDescriptor.m_CifgEnabled)
2794  {
2795  cellToInputWeights = ToConstTensor(flatBufferInputParams->cellToInputWeights());
2796  qLstmInputParams.m_CellToInputWeights = &cellToInputWeights;
2797  }
2798 
2799  cellToForgetWeights = ToConstTensor(flatBufferInputParams->cellToForgetWeights());
2800  cellToOutputWeights = ToConstTensor(flatBufferInputParams->cellToOutputWeights());
2801 
2802  qLstmInputParams.m_CellToForgetWeights = &cellToForgetWeights;
2803  qLstmInputParams.m_CellToOutputWeights = &cellToOutputWeights;
2804  }
2805 
2806  // Optional layer norm params
2807  armnn::ConstTensor inputLayerNormWeights;
2808  armnn::ConstTensor forgetLayerNormWeights;
2809  armnn::ConstTensor cellLayerNormWeights;
2810  armnn::ConstTensor outputLayerNormWeights;
2811 
2812  if (qLstmDescriptor.m_LayerNormEnabled)
2813  {
2814  if (!qLstmDescriptor.m_CifgEnabled)
2815  {
2816  inputLayerNormWeights = ToConstTensor(flatBufferInputParams->inputLayerNormWeights());
2817  qLstmInputParams.m_InputLayerNormWeights = &inputLayerNormWeights;
2818  }
2819 
2820  forgetLayerNormWeights = ToConstTensor(flatBufferInputParams->forgetLayerNormWeights());
2821  cellLayerNormWeights = ToConstTensor(flatBufferInputParams->cellLayerNormWeights());
2822  outputLayerNormWeights = ToConstTensor(flatBufferInputParams->outputLayerNormWeights());
2823 
2824  qLstmInputParams.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
2825  qLstmInputParams.m_CellLayerNormWeights = &cellLayerNormWeights;
2826  qLstmInputParams.m_OutputLayerNormWeights = &outputLayerNormWeights;
2827  }
2828 
2829  IConnectableLayer* layer = m_Network->AddQLstmLayer(qLstmDescriptor, qLstmInputParams, layerName.c_str());
2830 
2831  armnn::TensorInfo outputStateOutInfo = ToTensorInfo(outputs[0]);
2832  layer->GetOutputSlot(0).SetTensorInfo(outputStateOutInfo);
2833 
2834  armnn::TensorInfo cellStateOutInfo = ToTensorInfo(outputs[1]);
2835  layer->GetOutputSlot(1).SetTensorInfo(cellStateOutInfo);
2836 
2837  armnn::TensorInfo outputInfo = ToTensorInfo(outputs[2]);
2838  layer->GetOutputSlot(2).SetTensorInfo(outputInfo);
2839 
2840  RegisterInputSlots(graph, layerIndex, layer);
2841  RegisterOutputSlots(graph, layerIndex, layer);
2842 }
2843 
2844 void Deserializer::ParseQuantizedLstm(GraphPtr graph, unsigned int layerIndex)
2845 {
2846  CHECK_LAYERS(graph, 0, layerIndex);
2847 
2848  auto inputs = GetInputs(graph, layerIndex);
2849  CHECK_VALID_SIZE(inputs.size(), 3);
2850 
2851  auto outputs = GetOutputs(graph, layerIndex);
2852  CHECK_VALID_SIZE(outputs.size(), 2);
2853 
2854  auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_QuantizedLstmLayer();
2855  auto layerName = GetLayerName(graph, layerIndex);
2856  auto flatBufferInputParams = flatBufferLayer->inputParams();
2857 
2858  armnn::QuantizedLstmInputParams lstmInputParams;
2859 
2860  armnn::ConstTensor inputToInputWeights = ToConstTensor(flatBufferInputParams->inputToInputWeights());
2861  armnn::ConstTensor inputToForgetWeights = ToConstTensor(flatBufferInputParams->inputToForgetWeights());
2862  armnn::ConstTensor inputToCellWeights = ToConstTensor(flatBufferInputParams->inputToCellWeights());
2863  armnn::ConstTensor inputToOutputWeights = ToConstTensor(flatBufferInputParams->inputToOutputWeights());
2864  armnn::ConstTensor recurrentToInputWeights = ToConstTensor(flatBufferInputParams->recurrentToInputWeights());
2865  armnn::ConstTensor recurrentToForgetWeights = ToConstTensor(flatBufferInputParams->recurrentToForgetWeights());
2866  armnn::ConstTensor recurrentToCellWeights = ToConstTensor(flatBufferInputParams->recurrentToCellWeights());
2867  armnn::ConstTensor recurrentToOutputWeights = ToConstTensor(flatBufferInputParams->recurrentToOutputWeights());
2868  armnn::ConstTensor inputGateBias = ToConstTensor(flatBufferInputParams->inputGateBias());
2869  armnn::ConstTensor forgetGateBias = ToConstTensor(flatBufferInputParams->forgetGateBias());
2870  armnn::ConstTensor cellBias = ToConstTensor(flatBufferInputParams->cellBias());
2871  armnn::ConstTensor outputGateBias = ToConstTensor(flatBufferInputParams->outputGateBias());
2872 
2873  lstmInputParams.m_InputToInputWeights = &inputToInputWeights;
2874  lstmInputParams.m_InputToForgetWeights = &inputToForgetWeights;
2875  lstmInputParams.m_InputToCellWeights = &inputToCellWeights;
2876  lstmInputParams.m_InputToOutputWeights = &inputToOutputWeights;
2877  lstmInputParams.m_RecurrentToInputWeights = &recurrentToInputWeights;
2878  lstmInputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
2879  lstmInputParams.m_RecurrentToCellWeights = &recurrentToCellWeights;
2880  lstmInputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
2881  lstmInputParams.m_InputGateBias = &inputGateBias;
2882  lstmInputParams.m_ForgetGateBias = &forgetGateBias;
2883  lstmInputParams.m_CellBias = &cellBias;
2884  lstmInputParams.m_OutputGateBias = &outputGateBias;
2885 
2886  IConnectableLayer* layer = m_Network->AddQuantizedLstmLayer(lstmInputParams, layerName.c_str());
2887 
2888  armnn::TensorInfo outputTensorInfo1 = ToTensorInfo(outputs[0]);
2889  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo1);
2890 
2891  armnn::TensorInfo outputTensorInfo2 = ToTensorInfo(outputs[1]);
2892  layer->GetOutputSlot(1).SetTensorInfo(outputTensorInfo2);
2893 
2894  RegisterInputSlots(graph, layerIndex, layer);
2895  RegisterOutputSlots(graph, layerIndex, layer);
2896 }
2897 
2898 void Deserializer::ParseDequantize(GraphPtr graph, unsigned int layerIndex)
2899 {
2900  CHECK_LAYERS(graph, 0, layerIndex);
2901 
2902  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2903  CHECK_VALID_SIZE(inputs.size(), 1);
2904 
2905  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2906  CHECK_VALID_SIZE(outputs.size(), 1);
2907 
2908  const std::string layerName = GetLayerName(graph, layerIndex);
2909  IConnectableLayer* layer = m_Network->AddDequantizeLayer(layerName.c_str());
2910 
2911  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2912  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2913 
2914  RegisterInputSlots(graph, layerIndex, layer);
2915  RegisterOutputSlots(graph, layerIndex, layer);
2916 }
2917 
2918 void Deserializer::ParseMerge(GraphPtr graph, unsigned int layerIndex)
2919 {
2920  CHECK_LAYERS(graph, 0, layerIndex);
2921 
2922  Deserializer::TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
2923  CHECK_VALID_SIZE(inputs.size(), 2);
2924 
2925  Deserializer::TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
2926  CHECK_VALID_SIZE(outputs.size(), 1);
2927 
2928  const std::string layerName = GetLayerName(graph, layerIndex);
2929  IConnectableLayer* layer = m_Network->AddMergeLayer(layerName.c_str());
2930 
2931  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2932  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2933 
2934  RegisterInputSlots(graph, layerIndex, layer);
2935  RegisterOutputSlots(graph, layerIndex, layer);
2936 }
2937 
2938 void Deserializer::ParseSwitch(GraphPtr graph, unsigned int layerIndex)
2939 {
2940  CHECK_LAYERS(graph, 0, layerIndex);
2941  auto inputs = GetInputs(graph, layerIndex);
2942  CHECK_LOCATION();
2943  CHECK_VALID_SIZE(inputs.size(), 2);
2944 
2945  auto outputs = GetOutputs(graph, layerIndex);
2946  CHECK_VALID_SIZE(outputs.size(), 2);
2947 
2948  auto layerName = GetLayerName(graph, layerIndex);
2949  IConnectableLayer* layer = m_Network->AddSwitchLayer(layerName.c_str());
2950 
2951  armnn::TensorInfo output0TensorInfo = ToTensorInfo(outputs[0]);
2952  layer->GetOutputSlot(0).SetTensorInfo(output0TensorInfo);
2953 
2954  armnn::TensorInfo output1TensorInfo = ToTensorInfo(outputs[1]);
2955  layer->GetOutputSlot(1).SetTensorInfo(output1TensorInfo);
2956 
2957  RegisterInputSlots(graph, layerIndex, layer);
2958  RegisterOutputSlots(graph, layerIndex, layer);
2959 }
2960 
2961 void Deserializer::ParsePrelu(GraphPtr graph, unsigned int layerIndex)
2962 {
2963  CHECK_LAYERS(graph, 0, layerIndex);
2964  auto inputs = GetInputs(graph, layerIndex);
2965  CHECK_LOCATION();
2966  CHECK_VALID_SIZE(inputs.size(), 2);
2967 
2968  auto outputs = GetOutputs(graph, layerIndex);
2969  CHECK_VALID_SIZE(outputs.size(), 1);
2970 
2971  auto layerName = GetLayerName(graph, layerIndex);
2972  IConnectableLayer* layer = m_Network->AddPreluLayer(layerName.c_str());
2973 
2974  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
2975  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2976 
2977  RegisterInputSlots(graph, layerIndex, layer);
2978  RegisterOutputSlots(graph, layerIndex, layer);
2979 }
2980 
2981 void Deserializer::ParseTranspose(GraphPtr graph, unsigned int layerIndex)
2982 {
2983  CHECK_LAYERS(graph, 0, layerIndex);
2984 
2985  auto dimsMapping = graph->layers()->Get(layerIndex)->layer_as_TransposeLayer()->descriptor()->dimMappings();
2986 
2987  auto inputs = GetInputs(graph, layerIndex);
2988  CHECK_VALID_SIZE(inputs.size(), 1);
2989 
2990  auto outputs = GetOutputs(graph, layerIndex);
2991  CHECK_VALID_SIZE(outputs.size(), 1);
2992  auto outputInfo = ToTensorInfo(outputs[0]);
2993 
2994  auto layerName = GetLayerName(graph, layerIndex);
2995  const armnn::TransposeDescriptor descriptor(armnn::PermutationVector(dimsMapping->data(), dimsMapping->Length()));
2996 
2997  IConnectableLayer* layer = m_Network->AddTransposeLayer(descriptor, layerName.c_str());
2998  layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2999 
3000  RegisterInputSlots(graph, layerIndex, layer);
3001  RegisterOutputSlots(graph, layerIndex, layer);
3002 }
3003 
3004 void Deserializer::ParseTransposeConvolution2d(GraphPtr graph, unsigned int layerIndex)
3005 {
3006  CHECK_LAYERS(graph, 0, layerIndex);
3007 
3008  auto inputs = GetInputs(graph, layerIndex);
3009  CHECK_VALID_SIZE(inputs.size(), 1);
3010 
3011  auto outputs = GetOutputs(graph, layerIndex);
3012  CHECK_VALID_SIZE(outputs.size(), 1);
3013 
3014  auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_TransposeConvolution2dLayer();
3015  auto layerName = GetLayerName(graph, layerIndex);
3016  auto serializerDescriptor = serializerLayer->descriptor();
3017 
3019  descriptor.m_PadLeft = serializerDescriptor->padLeft();
3020  descriptor.m_PadRight = serializerDescriptor->padRight();
3021  descriptor.m_PadTop = serializerDescriptor->padTop();
3022  descriptor.m_PadBottom = serializerDescriptor->padBottom();
3023  descriptor.m_StrideX = serializerDescriptor->strideX();
3024  descriptor.m_StrideY = serializerDescriptor->strideY();;
3025  descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();;
3026  descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
3027 
3028  // weights & biases
3029  armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights());
3030  armnn::Optional<armnn::ConstTensor> optionalBiases;
3031  if (descriptor.m_BiasEnabled)
3032  {
3033  armnn::ConstTensor biases = ToConstTensor(serializerLayer->biases());
3034  optionalBiases = armnn::MakeOptional<armnn::ConstTensor>(biases);
3035  }
3036 
3037  IConnectableLayer* layer = m_Network->AddTransposeConvolution2dLayer(descriptor,
3038  weights,
3039  optionalBiases,
3040  layerName.c_str());
3041 
3042  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3043  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3044 
3045  RegisterInputSlots(graph, layerIndex, layer);
3046  RegisterOutputSlots(graph, layerIndex, layer);
3047 }
3048 
3049 void Deserializer::ParseStack(GraphPtr graph, unsigned int layerIndex)
3050 {
3051  CHECK_LAYERS(graph, 0, layerIndex);
3052  auto inputs = GetInputs(graph, layerIndex);
3053 
3054  auto outputs = GetOutputs(graph, layerIndex);
3055  CHECK_VALID_SIZE(outputs.size(), 1);
3056 
3057  auto flatBufferDescriptor = graph->layers()->Get(layerIndex)->layer_as_StackLayer()->descriptor();
3058  unsigned int axis = flatBufferDescriptor->axis();
3059  unsigned int numInputs = flatBufferDescriptor->numInputs();
3060  CHECK_VALID_SIZE(inputs.size(), numInputs);
3061 
3062  auto flatBufferInputShape = flatBufferDescriptor->inputShape();
3063  std::vector<uint32_t> vectorInputShape(flatBufferInputShape->begin(),
3064  flatBufferInputShape->begin() + flatBufferInputShape->size());
3065 
3066  TensorShape inputShape(static_cast<unsigned int>(vectorInputShape.size()), vectorInputShape.data());
3067  armnn::StackDescriptor descriptor(axis, numInputs, inputShape);
3068 
3069  for (unsigned int i=0; i<inputs.size(); ++i)
3070  {
3071  armnn::TensorShape inputShape = ToTensorInfo(inputs[i]).GetShape();
3072  if (descriptor.m_InputShape != inputShape)
3073  {
3074  std::stringstream ss;
3075  ss << "Shape of input "
3076  << i
3077  << " "
3078  << inputShape
3079  << " does not equal defined input shape "
3080  << descriptor.m_InputShape
3081  << ": "
3082  << CHECK_LOCATION().AsString();
3083  throw ParseException(ss.str());
3084  }
3085  }
3086 
3087  auto layerName = GetLayerName(graph, layerIndex);
3088  IConnectableLayer* layer = m_Network->AddStackLayer(descriptor, layerName.c_str());
3089 
3090  armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
3091  layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
3092 
3093  RegisterInputSlots(graph, layerIndex, layer);
3094  RegisterOutputSlots(graph, layerIndex, layer);
3095 }
3096 
3097 void Deserializer::ParseStandIn(GraphPtr graph, unsigned int layerIndex)
3098 {
3099  CHECK_LAYERS(graph, 0, layerIndex);
3100 
3101  auto inputs = GetInputs(graph, layerIndex);
3102  auto outputs = GetOutputs(graph, layerIndex);
3103 
3104  auto fbLayer = graph->layers()->Get(layerIndex)->layer_as_StandInLayer();
3105  auto fbDescriptor = fbLayer->descriptor();
3106 
3107  armnn::StandInDescriptor descriptor;
3108  descriptor.m_NumInputs = fbDescriptor->numInputs();
3109  descriptor.m_NumOutputs = fbDescriptor->numOutputs();
3110 
3111  CHECK_VALID_SIZE(inputs.size(), descriptor.m_NumInputs);
3112  CHECK_VALID_SIZE(outputs.size(), descriptor.m_NumOutputs);
3113 
3114  const std::string layerName = GetLayerName(graph, layerIndex);
3115  armnn::IConnectableLayer* layer = m_Network->AddStandInLayer(descriptor, layerName.c_str());
3116 
3117  for (unsigned int i = 0u; i < descriptor.m_NumOutputs; ++i)
3118  {
3119  armnn::TensorInfo outputInfo = ToTensorInfo(outputs[i]);
3120  layer->GetOutputSlot(i).SetTensorInfo(outputInfo);
3121  }
3122 
3123  RegisterInputSlots(graph, layerIndex, layer);
3124  RegisterOutputSlots(graph, layerIndex, layer);
3125 }
3126 
3127 } // namespace armnnDeserializer
armnn::ConstTensor ToConstTensor(Deserializer::ConstTensorRawPtr constTensorPtr)
static armnn::LstmDescriptor GetLstmDescriptor(LstmDescriptorPtr lstmDescriptor)
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
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.
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:61
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.
static GraphPtr LoadGraphFromBinary(const uint8_t *binaryContent, size_t len)
virtual unsigned int GetNumInputSlots() const =0
Returns the number of connectable input slots.
DataLayout
Definition: Types.hpp:50
float m_K
Kappa value used for the across channel normalization equation.
A TransposeConvolution2dDescriptor for the TransposeConvolution2dLayer.
const TensorShape & GetShape() const
Definition: Tensor.hpp:187
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.
std::string AsString() const
Definition: Exceptions.hpp:29
static armnn::NormalizationDescriptor GetNormalizationDescriptor(NormalizationDescriptorPtr normalizationDescriptor, unsigned int layerIndex)
A ReshapeDescriptor for the ReshapeLayer.
static void Destroy(IDeserializer *parser)
const ConstTensor * m_CellToOutputWeights
Definition: LstmParams.hpp:50
const ConstTensor * m_RecurrentToForgetWeights
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
A ComparisonDescriptor for the ComparisonLayer.
Definition: Descriptors.hpp:73
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.
#define CHECK_TENSOR_PTR(TENSOR_PTR)
A Convolution2dDescriptor for the Convolution2dLayer.
float m_Alpha
Alpha value for the normalization equation.
const armnnSerializer::TensorInfo * TensorRawPtr
const armnnSerializer::NormalizationDescriptor * NormalizationDescriptorPtr
uint32_t m_PadLeft
Padding left value in the width dimension.
float m_HiddenStateScale
Hidden State quantization scale.
bool m_BiasEnabled
Enable/disable bias.
const ConstTensor * m_CellToInputWeights
Definition: LstmParams.hpp:48
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.
std::vector< unsigned int > m_Size
Size of the slice in each dimension.
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:65
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)
static armnn::QLstmDescriptor GetQLstmDescriptor(QLstmDescriptorPtr qLstmDescriptorPtr)
static IDeserializerPtr Create()
uint32_t m_PadTop
Padding top value in the height dimension.
const ConstTensor * m_RecurrentToCellWeights
Definition: LstmParams.hpp:46
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).
const ConstTensor * m_ForgetLayerNormWeights
Definition: LstmParams.hpp:58
const ConstTensor * m_CellToForgetWeights
Definition: LstmParams.hpp:49
Copyright (c) 2020 ARM Limited.
void IgnoreUnused(Ts &&...)
armnn::INetworkPtr CreateNetworkFromBinary(const std::vector< uint8_t > &binaryContent) override
Create an input network from binary file contents.
uint32_t m_PadBottom
Padding bottom value in the height dimension.
#define CHECK_GRAPH(GRAPH, LAYERS_INDEX)
static std::string GetLayerName(const GraphPtr &graph, unsigned int index)
uint32_t m_DilationY
Dilation along y axis.
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
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_DilationY
Dilation factor value for height dimension.
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:88
BindingPointInfo GetNetworkInputBindingInfo(unsigned int layerId, const std::string &name) const override
Retrieve binding info (layer id and tensor info) for the network input identified by the given layer ...
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:202
const ConstTensor * m_OutputGateBias
Definition: LstmParams.hpp:54
armnn::ComparisonOperation ToComparisonOperation(armnnSerializer::ComparisonOperation operation)
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
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:189
A ResizeDescriptor for the ResizeLayer.
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.
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.
static int32_t GetBindingLayerInfo(const GraphPtr &graphPtr, unsigned int layerIndex)
const armnnSerializer::Pooling2dDescriptor * PoolingDescriptor
#define CHECK_CONST_TENSOR_SIZE(CONST_TENSOR_SIZE, TENSOR_SIZE)
armnn::TensorInfo ToTensorInfo(Deserializer::TensorRawPtr tensorPtr)
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
const ConstTensor * m_InputLayerNormWeights
Definition: LstmParams.hpp:57
ComparisonOperation
Definition: Types.hpp:78
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
bool m_LayerNormEnabled
Enable/disable layer normalization.
armnn::DataLayout ToDataLayout(armnnSerializer::DataLayout dataLayout)
bool CheckShape(const armnn::TensorShape &actual, const std::vector< uint32_t > &expected)
DataType
Definition: Types.hpp:32
float m_NmsIouThreshold
Intersection over union threshold.
const ConstTensor * m_RecurrentToOutputWeights
Definition: LstmParams.hpp:47
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...
armnnSerializer::TensorInfo * TensorRawPtr
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:37
A L2NormalizationDescriptor for the L2NormalizationLayer.
const ConstTensor * m_ProjectionBias
Definition: LstmParams.hpp:56
const ConstTensor * m_InputToForgetWeights
An ArgMinMaxDescriptor for ArgMinMaxLayer.
Definition: Descriptors.hpp:51
An OriginsDescriptor for the ConcatLayer.
float m_ProjectionClip
Clipping threshold value for the projection.
static LayerBaseRawPtr GetBaseLayer(const GraphPtr &graphPtr, unsigned int layerIndex)
A FullyConnectedDescriptor for the FullyConnectedLayer.
bool m_BiasEnabled
Enable/disable bias.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:314
float m_InputIntermediateScale
Input intermediate quantization scale.
uint32_t m_TargetWidth
Target width value.
A GatherDescriptor for the GatherLayer.
#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::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.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
BindingPointInfo GetNetworkOutputBindingInfo(unsigned int layerId, const std::string &name) const override
Retrieve binding info (layer id and tensor info) for the network output identified by the given layer...
std::vector< unsigned int > m_BlockShape
Block shape value.
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
min(a, max(b, input)) ReLu1 & ReLu6.
#define CHECK_LOCATION()
Definition: Exceptions.hpp:197
std::vector< TensorRawPtr > TensorRawPtrVector
uint32_t m_TargetHeight
Target height value.
uint32_t m_ActivationFunc
The activation function to use.
A SliceDescriptor for the SliceLayer.
uint32_t m_StrideY
Stride value when proceeding through input for the height 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).
static TensorRawPtrVector GetOutputs(const GraphPtr &graph, unsigned int layerIndex)
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)
float m_ScaleH
Center size encoding scale height.
ComparisonOperation m_Operation
Specifies the comparison operation to execute.
Definition: Descriptors.hpp:89
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
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:45
uint32_t m_DilationX
Dilation along x axis.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
bool m_CifgEnabled
Enable/disable cifg (coupled input & forget gate).
armnn::ArgMinMaxFunction ToArgMinMaxFunction(armnnSerializer::ArgMinMaxFunction function)
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.
const armnnSerializer::SerializedGraph * GraphPtr
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.
Definition: Descriptors.hpp:93
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.
static IDeserializer * CreateRaw()
uint32_t m_StrideY
Stride value when proceeding through input for the height 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
const armnnSerializer::ConstTensor * ConstTensorRawPtr
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
bool m_ProjectionEnabled
Enable/disable the projection layer.
Jarret 2009: Local Contrast Normalization.
ArgMinMaxFunction
Definition: Types.hpp:72
const armnnSerializer::LstmDescriptor * LstmDescriptorPtr
OutputShapeRounding m_OutputShapeRounding
The rounding method for the output shape. (Floor, Ceiling).
uint32_t m_NumInputs
Number of input tensors.
static armnn::Pooling2dDescriptor GetPoolingDescriptor(PoolingDescriptor pooling2dDescriptor, unsigned int layerIndex)
const armnnSerializer::QLstmDescriptor * QLstmDescriptorPtr
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:111
const ConstTensor * m_RecurrentToInputWeights
Definition: LstmParams.hpp:44
A MeanDescriptor for the MeanLayer.
const ConstTensor * m_InputToOutputWeights
UnaryOperation
Definition: Types.hpp:94
static TensorRawPtrVector GetInputs(const GraphPtr &graph, unsigned int layerIndex)
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
uint32_t m_PadRight
Padding right value in the width dimension.
A TransposeDescriptor for the TransposeLayer.
A StridedSliceDescriptor for the StridedSliceLayer.
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:67
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:101
virtual int Connect(IInputSlot &destination)=0
Krichevsky 2012: Local Brightness Normalization.
const char * m_Function
Definition: Exceptions.hpp:16
A Pooling2dDescriptor for the Pooling2dLayer.
const ConstTensor * m_OutputLayerNormWeights
Definition: LstmParams.hpp:60
const armnnSerializer::LayerBase * LayerBaseRawPtr
A NormalizationDescriptor for the NormalizationLayer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
An InstanceNormalizationDescriptor for InstanceNormalizationLayer.
float m_CellIntermediateScale
Cell intermediate quantization scale.
static armnn::TensorInfo OutputShapeOfReshape(const armnn::TensorInfo &inputTensorInfo, const std::vector< uint32_t > &targetDimsIn)
float m_B
Beta lower bound value used by the activation functions. (BoundedReLu, Linear, TanH).
Definition: Descriptors.hpp:47
A SoftmaxDescriptor for the SoftmaxLayer.
float m_Beta
Beta value for the normalization equation.
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:43
An input connection slot for a layer.
Definition: INetwork.hpp:24
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
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:192
const ConstTensor * m_InputToForgetWeights
Definition: LstmParams.hpp:41
ActivationFunction
Definition: Types.hpp:56
A PermuteDescriptor for the PermuteLayer.
uint32_t m_PadRight
Padding right value in the width dimension.
int32_t m_HiddenStateZeroPoint
Hidden State zero point.
const ConstTensor * m_InputToInputWeights
Definition: LstmParams.hpp:40
std::vector< float > anchors({ 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 100.5f, 1.0f, 1.0f })