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