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