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