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