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