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