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