IVGCVSW-5593 Implement Pimpl Idiom for serialization classes
[platform/upstream/armnn.git] / src / armnnSerializer / test / SerializerTests.cpp
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "../Serializer.hpp"
7
8 #include <armnn/Descriptors.hpp>
9 #include <armnn/INetwork.hpp>
10 #include <armnn/TypesUtils.hpp>
11 #include <armnn/LstmParams.hpp>
12 #include <armnn/QuantizedLstmParams.hpp>
13 #include <armnnDeserializer/IDeserializer.hpp>
14
15 #include <random>
16 #include <vector>
17
18 #include <boost/test/unit_test.hpp>
19
20 using armnnDeserializer::IDeserializer;
21
22 namespace
23 {
24
25 #define DECLARE_LAYER_VERIFIER_CLASS(name) \
26 class name##LayerVerifier : public LayerVerifierBase \
27 { \
28 public: \
29     name##LayerVerifier(const std::string& layerName, \
30                         const std::vector<armnn::TensorInfo>& inputInfos, \
31                         const std::vector<armnn::TensorInfo>& outputInfos) \
32         : LayerVerifierBase(layerName, inputInfos, outputInfos) {} \
33 \
34     void Visit##name##Layer(const armnn::IConnectableLayer* layer, const char* name) override \
35     { \
36         VerifyNameAndConnections(layer, name); \
37     } \
38 };
39
40 #define DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(name) \
41 class name##LayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::name##Descriptor> \
42 { \
43 public: \
44     name##LayerVerifier(const std::string& layerName, \
45                         const std::vector<armnn::TensorInfo>& inputInfos, \
46                         const std::vector<armnn::TensorInfo>& outputInfos, \
47                         const armnn::name##Descriptor& descriptor) \
48         : LayerVerifierBaseWithDescriptor<armnn::name##Descriptor>( \
49             layerName, inputInfos, outputInfos, descriptor) {} \
50 \
51     void Visit##name##Layer(const armnn::IConnectableLayer* layer, \
52                             const armnn::name##Descriptor& descriptor, \
53                             const char* name) override \
54     { \
55         VerifyNameAndConnections(layer, name); \
56         VerifyDescriptor(descriptor); \
57     } \
58 };
59
60 struct DefaultLayerVerifierPolicy
61 {
62     static void Apply(const std::string)
63     {
64         BOOST_TEST_MESSAGE("Unexpected layer found in network");
65         BOOST_TEST(false);
66     }
67 };
68
69 class LayerVerifierBase : public armnn::LayerVisitorBase<DefaultLayerVerifierPolicy>
70 {
71 public:
72     LayerVerifierBase(const std::string& layerName,
73                       const std::vector<armnn::TensorInfo>& inputInfos,
74                       const std::vector<armnn::TensorInfo>& outputInfos)
75     : m_LayerName(layerName)
76     , m_InputTensorInfos(inputInfos)
77     , m_OutputTensorInfos(outputInfos) {}
78
79     void VisitInputLayer(const armnn::IConnectableLayer*, armnn::LayerBindingId, const char*) override {}
80
81     void VisitOutputLayer(const armnn::IConnectableLayer*, armnn::LayerBindingId, const char*) override {}
82
83 protected:
84     void VerifyNameAndConnections(const armnn::IConnectableLayer* layer, const char* name)
85     {
86         BOOST_TEST(name == m_LayerName.c_str());
87
88         BOOST_TEST(layer->GetNumInputSlots() == m_InputTensorInfos.size());
89         BOOST_TEST(layer->GetNumOutputSlots() == m_OutputTensorInfos.size());
90
91         for (unsigned int i = 0; i < m_InputTensorInfos.size(); i++)
92         {
93             const armnn::IOutputSlot* connectedOutput = layer->GetInputSlot(i).GetConnection();
94             BOOST_CHECK(connectedOutput);
95
96             const armnn::TensorInfo& connectedInfo = connectedOutput->GetTensorInfo();
97             BOOST_TEST(connectedInfo.GetShape() == m_InputTensorInfos[i].GetShape());
98             BOOST_TEST(
99                 GetDataTypeName(connectedInfo.GetDataType()) == GetDataTypeName(m_InputTensorInfos[i].GetDataType()));
100
101             BOOST_TEST(connectedInfo.GetQuantizationScale() == m_InputTensorInfos[i].GetQuantizationScale());
102             BOOST_TEST(connectedInfo.GetQuantizationOffset() == m_InputTensorInfos[i].GetQuantizationOffset());
103         }
104
105         for (unsigned int i = 0; i < m_OutputTensorInfos.size(); i++)
106         {
107             const armnn::TensorInfo& outputInfo = layer->GetOutputSlot(i).GetTensorInfo();
108             BOOST_TEST(outputInfo.GetShape() == m_OutputTensorInfos[i].GetShape());
109             BOOST_TEST(
110                 GetDataTypeName(outputInfo.GetDataType()) == GetDataTypeName(m_OutputTensorInfos[i].GetDataType()));
111
112             BOOST_TEST(outputInfo.GetQuantizationScale() == m_OutputTensorInfos[i].GetQuantizationScale());
113             BOOST_TEST(outputInfo.GetQuantizationOffset() == m_OutputTensorInfos[i].GetQuantizationOffset());
114         }
115     }
116
117     void VerifyConstTensors(const std::string& tensorName,
118                             const armnn::ConstTensor* expectedPtr,
119                             const armnn::ConstTensor* actualPtr)
120     {
121         if (expectedPtr == nullptr)
122         {
123             BOOST_CHECK_MESSAGE(actualPtr == nullptr, tensorName + " should not exist");
124         }
125         else
126         {
127             BOOST_CHECK_MESSAGE(actualPtr != nullptr, tensorName + " should have been set");
128             if (actualPtr != nullptr)
129             {
130                 const armnn::TensorInfo& expectedInfo = expectedPtr->GetInfo();
131                 const armnn::TensorInfo& actualInfo = actualPtr->GetInfo();
132
133                 BOOST_CHECK_MESSAGE(expectedInfo.GetShape() == actualInfo.GetShape(),
134                                     tensorName + " shapes don't match");
135                 BOOST_CHECK_MESSAGE(
136                         GetDataTypeName(expectedInfo.GetDataType()) == GetDataTypeName(actualInfo.GetDataType()),
137                         tensorName + " data types don't match");
138
139                 BOOST_CHECK_MESSAGE(expectedPtr->GetNumBytes() == actualPtr->GetNumBytes(),
140                                     tensorName + " (GetNumBytes) data sizes do not match");
141                 if (expectedPtr->GetNumBytes() == actualPtr->GetNumBytes())
142                 {
143                     //check the data is identical
144                     const char* expectedData = static_cast<const char*>(expectedPtr->GetMemoryArea());
145                     const char* actualData = static_cast<const char*>(actualPtr->GetMemoryArea());
146                     bool same = true;
147                     for (unsigned int i = 0; i < expectedPtr->GetNumBytes(); ++i)
148                     {
149                         same = expectedData[i] == actualData[i];
150                         if (!same)
151                         {
152                             break;
153                         }
154                     }
155                     BOOST_CHECK_MESSAGE(same, tensorName + " data does not match");
156                 }
157             }
158         }
159     }
160
161 private:
162     std::string m_LayerName;
163     std::vector<armnn::TensorInfo> m_InputTensorInfos;
164     std::vector<armnn::TensorInfo> m_OutputTensorInfos;
165 };
166
167 template<typename Descriptor>
168 class LayerVerifierBaseWithDescriptor : public LayerVerifierBase
169 {
170 public:
171     LayerVerifierBaseWithDescriptor(const std::string& layerName,
172                                     const std::vector<armnn::TensorInfo>& inputInfos,
173                                     const std::vector<armnn::TensorInfo>& outputInfos,
174                                     const Descriptor& descriptor)
175         : LayerVerifierBase(layerName, inputInfos, outputInfos)
176         , m_Descriptor(descriptor) {}
177
178 protected:
179     void VerifyDescriptor(const Descriptor& descriptor)
180     {
181         BOOST_CHECK(descriptor == m_Descriptor);
182     }
183
184     Descriptor m_Descriptor;
185 };
186
187 template<typename T>
188 void CompareConstTensorData(const void* data1, const void* data2, unsigned int numElements)
189 {
190     T typedData1 = static_cast<T>(data1);
191     T typedData2 = static_cast<T>(data2);
192     BOOST_CHECK(typedData1);
193     BOOST_CHECK(typedData2);
194
195     for (unsigned int i = 0; i < numElements; i++)
196     {
197         BOOST_TEST(typedData1[i] == typedData2[i]);
198     }
199 }
200
201 void CompareConstTensor(const armnn::ConstTensor& tensor1, const armnn::ConstTensor& tensor2)
202 {
203     BOOST_TEST(tensor1.GetShape() == tensor2.GetShape());
204     BOOST_TEST(GetDataTypeName(tensor1.GetDataType()) == GetDataTypeName(tensor2.GetDataType()));
205
206     switch (tensor1.GetDataType())
207     {
208         case armnn::DataType::Float32:
209             CompareConstTensorData<const float*>(
210                 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
211             break;
212         case armnn::DataType::QAsymmU8:
213         case armnn::DataType::Boolean:
214             CompareConstTensorData<const uint8_t*>(
215                 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
216             break;
217         case armnn::DataType::QSymmS8:
218             CompareConstTensorData<const int8_t*>(
219                 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
220             break;
221         case armnn::DataType::Signed32:
222             CompareConstTensorData<const int32_t*>(
223                 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
224             break;
225         default:
226             // Note that Float16 is not yet implemented
227             BOOST_TEST_MESSAGE("Unexpected datatype");
228             BOOST_TEST(false);
229     }
230 }
231
232 armnn::INetworkPtr DeserializeNetwork(const std::string& serializerString)
233 {
234     std::vector<std::uint8_t> const serializerVector{serializerString.begin(), serializerString.end()};
235     return IDeserializer::Create()->CreateNetworkFromBinary(serializerVector);
236 }
237
238 std::string SerializeNetwork(const armnn::INetwork& network)
239 {
240     armnnSerializer::ISerializerPtr serializer = armnnSerializer::ISerializer::Create();
241
242     serializer->Serialize(network);
243
244     std::stringstream stream;
245     serializer->SaveSerializedToStream(stream);
246
247     std::string serializerString{stream.str()};
248     return serializerString;
249 }
250
251 template<typename DataType>
252 static std::vector<DataType> GenerateRandomData(size_t size)
253 {
254     constexpr bool isIntegerType = std::is_integral<DataType>::value;
255     using Distribution =
256         typename std::conditional<isIntegerType,
257                                   std::uniform_int_distribution<DataType>,
258                                   std::uniform_real_distribution<DataType>>::type;
259
260     static constexpr DataType lowerLimit = std::numeric_limits<DataType>::min();
261     static constexpr DataType upperLimit = std::numeric_limits<DataType>::max();
262
263     static Distribution distribution(lowerLimit, upperLimit);
264     static std::default_random_engine generator;
265
266     std::vector<DataType> randomData(size);
267     std::generate(randomData.begin(), randomData.end(), []() { return distribution(generator); });
268
269     return randomData;
270 }
271
272 } // anonymous namespace
273
274 BOOST_AUTO_TEST_SUITE(SerializerTests)
275
276 BOOST_AUTO_TEST_CASE(SerializeAddition)
277 {
278     DECLARE_LAYER_VERIFIER_CLASS(Addition)
279
280     const std::string layerName("addition");
281     const armnn::TensorInfo tensorInfo({1, 2, 3}, armnn::DataType::Float32);
282
283     armnn::INetworkPtr network = armnn::INetwork::Create();
284     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
285     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
286     armnn::IConnectableLayer* const additionLayer = network->AddAdditionLayer(layerName.c_str());
287     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
288
289     inputLayer0->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(0));
290     inputLayer1->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(1));
291     additionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
292
293     inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
294     inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
295     additionLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
296
297     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
298     BOOST_CHECK(deserializedNetwork);
299
300     AdditionLayerVerifier verifier(layerName, {tensorInfo, tensorInfo}, {tensorInfo});
301     deserializedNetwork->Accept(verifier);
302 }
303
304 BOOST_AUTO_TEST_CASE(SerializeArgMinMax)
305 {
306     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(ArgMinMax)
307
308     const std::string layerName("argminmax");
309     const armnn::TensorInfo inputInfo({1, 2, 3}, armnn::DataType::Float32);
310     const armnn::TensorInfo outputInfo({1, 3}, armnn::DataType::Signed32);
311
312     armnn::ArgMinMaxDescriptor descriptor;
313     descriptor.m_Function = armnn::ArgMinMaxFunction::Max;
314     descriptor.m_Axis = 1;
315
316     armnn::INetworkPtr network = armnn::INetwork::Create();
317     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
318     armnn::IConnectableLayer* const argMinMaxLayer = network->AddArgMinMaxLayer(descriptor, layerName.c_str());
319     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
320
321     inputLayer->GetOutputSlot(0).Connect(argMinMaxLayer->GetInputSlot(0));
322     argMinMaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
323
324     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
325     argMinMaxLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
326
327     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
328     BOOST_CHECK(deserializedNetwork);
329
330     ArgMinMaxLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
331     deserializedNetwork->Accept(verifier);
332 }
333
334 BOOST_AUTO_TEST_CASE(SerializeBatchNormalization)
335 {
336     using Descriptor = armnn::BatchNormalizationDescriptor;
337     class BatchNormalizationLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
338     {
339     public:
340         BatchNormalizationLayerVerifier(const std::string& layerName,
341                                         const std::vector<armnn::TensorInfo>& inputInfos,
342                                         const std::vector<armnn::TensorInfo>& outputInfos,
343                                         const Descriptor& descriptor,
344                                         const armnn::ConstTensor& mean,
345                                         const armnn::ConstTensor& variance,
346                                         const armnn::ConstTensor& beta,
347                                         const armnn::ConstTensor& gamma)
348             : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
349             , m_Mean(mean)
350             , m_Variance(variance)
351             , m_Beta(beta)
352             , m_Gamma(gamma) {}
353
354         void VisitBatchNormalizationLayer(const armnn::IConnectableLayer* layer,
355                                           const Descriptor& descriptor,
356                                           const armnn::ConstTensor& mean,
357                                           const armnn::ConstTensor& variance,
358                                           const armnn::ConstTensor& beta,
359                                           const armnn::ConstTensor& gamma,
360                                           const char* name) override
361         {
362             VerifyNameAndConnections(layer, name);
363             VerifyDescriptor(descriptor);
364
365             CompareConstTensor(mean, m_Mean);
366             CompareConstTensor(variance, m_Variance);
367             CompareConstTensor(beta, m_Beta);
368             CompareConstTensor(gamma, m_Gamma);
369         }
370
371     private:
372         armnn::ConstTensor m_Mean;
373         armnn::ConstTensor m_Variance;
374         armnn::ConstTensor m_Beta;
375         armnn::ConstTensor m_Gamma;
376     };
377
378     const std::string layerName("batchNormalization");
379     const armnn::TensorInfo inputInfo ({ 1, 3, 3, 1 }, armnn::DataType::Float32);
380     const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
381
382     const armnn::TensorInfo meanInfo({1}, armnn::DataType::Float32);
383     const armnn::TensorInfo varianceInfo({1}, armnn::DataType::Float32);
384     const armnn::TensorInfo betaInfo({1}, armnn::DataType::Float32);
385     const armnn::TensorInfo gammaInfo({1}, armnn::DataType::Float32);
386
387     armnn::BatchNormalizationDescriptor descriptor;
388     descriptor.m_Eps = 0.0010000000475f;
389     descriptor.m_DataLayout = armnn::DataLayout::NHWC;
390
391     std::vector<float> meanData({5.0});
392     std::vector<float> varianceData({2.0});
393     std::vector<float> betaData({1.0});
394     std::vector<float> gammaData({0.0});
395
396     armnn::ConstTensor mean(meanInfo, meanData);
397     armnn::ConstTensor variance(varianceInfo, varianceData);
398     armnn::ConstTensor beta(betaInfo, betaData);
399     armnn::ConstTensor gamma(gammaInfo, gammaData);
400
401     armnn::INetworkPtr network = armnn::INetwork::Create();
402     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
403     armnn::IConnectableLayer* const batchNormalizationLayer =
404         network->AddBatchNormalizationLayer(descriptor, mean, variance, beta, gamma, layerName.c_str());
405     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
406
407     inputLayer->GetOutputSlot(0).Connect(batchNormalizationLayer->GetInputSlot(0));
408     batchNormalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
409
410     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
411     batchNormalizationLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
412
413     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
414     BOOST_CHECK(deserializedNetwork);
415
416     BatchNormalizationLayerVerifier verifier(
417         layerName, {inputInfo}, {outputInfo}, descriptor, mean, variance, beta, gamma);
418     deserializedNetwork->Accept(verifier);
419 }
420
421 BOOST_AUTO_TEST_CASE(SerializeBatchToSpaceNd)
422 {
423     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(BatchToSpaceNd)
424
425     const std::string layerName("spaceToBatchNd");
426     const armnn::TensorInfo inputInfo({4, 1, 2, 2}, armnn::DataType::Float32);
427     const armnn::TensorInfo outputInfo({1, 1, 4, 4}, armnn::DataType::Float32);
428
429     armnn::BatchToSpaceNdDescriptor desc;
430     desc.m_DataLayout = armnn::DataLayout::NCHW;
431     desc.m_BlockShape = {2, 2};
432     desc.m_Crops = {{0, 0}, {0, 0}};
433
434     armnn::INetworkPtr network = armnn::INetwork::Create();
435     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
436     armnn::IConnectableLayer* const batchToSpaceNdLayer = network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
437     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
438
439     inputLayer->GetOutputSlot(0).Connect(batchToSpaceNdLayer->GetInputSlot(0));
440     batchToSpaceNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
441
442     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
443     batchToSpaceNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
444
445     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
446     BOOST_CHECK(deserializedNetwork);
447
448     BatchToSpaceNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
449     deserializedNetwork->Accept(verifier);
450 }
451
452 BOOST_AUTO_TEST_CASE(SerializeComparison)
453 {
454     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Comparison)
455
456     const std::string layerName("comparison");
457
458     const armnn::TensorShape shape{2, 1, 2, 4};
459
460     const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Float32);
461     const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
462
463     armnn::ComparisonDescriptor descriptor(armnn::ComparisonOperation::NotEqual);
464
465     armnn::INetworkPtr network = armnn::INetwork::Create();
466     armnn::IConnectableLayer* const inputLayer0     = network->AddInputLayer(0);
467     armnn::IConnectableLayer* const inputLayer1     = network->AddInputLayer(1);
468     armnn::IConnectableLayer* const comparisonLayer = network->AddComparisonLayer(descriptor, layerName.c_str());
469     armnn::IConnectableLayer* const outputLayer     = network->AddOutputLayer(0);
470
471     inputLayer0->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(0));
472     inputLayer1->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(1));
473     comparisonLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
474
475     inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
476     inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
477     comparisonLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
478
479     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
480     BOOST_CHECK(deserializedNetwork);
481
482     ComparisonLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo }, descriptor);
483     deserializedNetwork->Accept(verifier);
484 }
485
486 BOOST_AUTO_TEST_CASE(SerializeConstant)
487 {
488     class ConstantLayerVerifier : public LayerVerifierBase
489     {
490     public:
491         ConstantLayerVerifier(const std::string& layerName,
492                               const std::vector<armnn::TensorInfo>& inputInfos,
493                               const std::vector<armnn::TensorInfo>& outputInfos,
494                               const armnn::ConstTensor& layerInput)
495             : LayerVerifierBase(layerName, inputInfos, outputInfos)
496             , m_LayerInput(layerInput) {}
497
498         void VisitConstantLayer(const armnn::IConnectableLayer* layer,
499                                 const armnn::ConstTensor& input,
500                                 const char* name) override
501         {
502             VerifyNameAndConnections(layer, name);
503             CompareConstTensor(input, m_LayerInput);
504         }
505
506         void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
507
508     private:
509         armnn::ConstTensor m_LayerInput;
510     };
511
512     const std::string layerName("constant");
513     const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
514
515     std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
516     armnn::ConstTensor constTensor(info, constantData);
517
518     armnn::INetworkPtr network(armnn::INetwork::Create());
519     armnn::IConnectableLayer* input = network->AddInputLayer(0);
520     armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
521     armnn::IConnectableLayer* add = network->AddAdditionLayer();
522     armnn::IConnectableLayer* output = network->AddOutputLayer(0);
523
524     input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
525     constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
526     add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
527
528     input->GetOutputSlot(0).SetTensorInfo(info);
529     constant->GetOutputSlot(0).SetTensorInfo(info);
530     add->GetOutputSlot(0).SetTensorInfo(info);
531
532     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
533     BOOST_CHECK(deserializedNetwork);
534
535     ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
536     deserializedNetwork->Accept(verifier);
537 }
538
539 BOOST_AUTO_TEST_CASE(SerializeConvolution2d)
540 {
541     using Descriptor = armnn::Convolution2dDescriptor;
542     class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
543     {
544     public:
545         Convolution2dLayerVerifier(const std::string& layerName,
546                                    const std::vector<armnn::TensorInfo>& inputInfos,
547                                    const std::vector<armnn::TensorInfo>& outputInfos,
548                                    const Descriptor& descriptor,
549                                    const armnn::ConstTensor& weights,
550                                    const armnn::Optional<armnn::ConstTensor>& biases)
551             : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
552             , m_Weights(weights)
553             , m_Biases(biases) {}
554
555         void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
556                                      const Descriptor& descriptor,
557                                      const armnn::ConstTensor& weights,
558                                      const armnn::Optional<armnn::ConstTensor>& biases,
559                                      const char* name) override
560         {
561             VerifyNameAndConnections(layer, name);
562             VerifyDescriptor(descriptor);
563
564             // check weights
565             CompareConstTensor(weights, m_Weights);
566
567             // check biases
568             BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
569             BOOST_CHECK(biases.has_value() == m_Biases.has_value());
570
571             if (biases.has_value() && m_Biases.has_value())
572             {
573                 CompareConstTensor(biases.value(), m_Biases.value());
574             }
575         }
576
577     private:
578         armnn::ConstTensor                  m_Weights;
579         armnn::Optional<armnn::ConstTensor> m_Biases;
580     };
581
582     const std::string layerName("convolution2d");
583     const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
584     const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
585
586     const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
587     const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
588
589     std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
590     armnn::ConstTensor weights(weightsInfo, weightsData);
591
592     std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
593     armnn::ConstTensor biases(biasesInfo, biasesData);
594
595     armnn::Convolution2dDescriptor descriptor;
596     descriptor.m_PadLeft     = 1;
597     descriptor.m_PadRight    = 1;
598     descriptor.m_PadTop      = 1;
599     descriptor.m_PadBottom   = 1;
600     descriptor.m_StrideX     = 2;
601     descriptor.m_StrideY     = 2;
602     descriptor.m_DilationX   = 2;
603     descriptor.m_DilationY   = 2;
604     descriptor.m_BiasEnabled = true;
605     descriptor.m_DataLayout  = armnn::DataLayout::NHWC;
606
607     armnn::INetworkPtr network = armnn::INetwork::Create();
608     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
609     armnn::IConnectableLayer* const convLayer   =
610             network->AddConvolution2dLayer(descriptor,
611                                            weights,
612                                            armnn::Optional<armnn::ConstTensor>(biases),
613                                            layerName.c_str());
614     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
615
616     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
617     convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
618
619     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
620     convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
621
622     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
623     BOOST_CHECK(deserializedNetwork);
624
625     Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
626     deserializedNetwork->Accept(verifier);
627 }
628
629 BOOST_AUTO_TEST_CASE(SerializeConvolution2dWithPerAxisParams)
630 {
631     using Descriptor = armnn::Convolution2dDescriptor;
632     class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
633     {
634     public:
635         Convolution2dLayerVerifier(const std::string& layerName,
636                                    const std::vector<armnn::TensorInfo>& inputInfos,
637                                    const std::vector<armnn::TensorInfo>& outputInfos,
638                                    const Descriptor& descriptor,
639                                    const armnn::ConstTensor& weights,
640                                    const armnn::Optional<armnn::ConstTensor>& biases)
641             : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
642             , m_Weights(weights)
643             , m_Biases(biases) {}
644
645         void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
646                                      const Descriptor& descriptor,
647                                      const armnn::ConstTensor& weights,
648                                      const armnn::Optional<armnn::ConstTensor>& biases,
649                                      const char* name) override
650         {
651             VerifyNameAndConnections(layer, name);
652             VerifyDescriptor(descriptor);
653
654             // check weights
655             CompareConstTensor(weights, m_Weights);
656
657             // check biases
658             BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
659             BOOST_CHECK(biases.has_value() == m_Biases.has_value());
660
661             if (biases.has_value() && m_Biases.has_value())
662             {
663                 CompareConstTensor(biases.value(), m_Biases.value());
664             }
665         }
666
667     private:
668         armnn::ConstTensor                  m_Weights;
669         armnn::Optional<armnn::ConstTensor> m_Biases;
670     };
671
672     using namespace armnn;
673
674     const std::string layerName("convolution2dWithPerAxis");
675     const TensorInfo inputInfo ({ 1, 3, 1, 2 }, DataType::QAsymmU8, 0.55f, 128);
676     const TensorInfo outputInfo({ 1, 3, 1, 3 }, DataType::QAsymmU8, 0.75f, 128);
677
678     const std::vector<float> quantScales{ 0.75f, 0.65f, 0.85f };
679     constexpr unsigned int quantDimension = 0;
680
681     const TensorInfo kernelInfo({ 3, 1, 1, 2 }, DataType::QSymmS8, quantScales, quantDimension);
682
683     const std::vector<float> biasQuantScales{ 0.25f, 0.50f, 0.75f };
684     const TensorInfo biasInfo({ 3 }, DataType::Signed32, biasQuantScales, quantDimension);
685
686     std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
687     armnn::ConstTensor weights(kernelInfo, kernelData);
688     std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
689     armnn::ConstTensor biases(biasInfo, biasData);
690
691     Convolution2dDescriptor descriptor;
692     descriptor.m_StrideX     = 1;
693     descriptor.m_StrideY     = 1;
694     descriptor.m_PadLeft     = 0;
695     descriptor.m_PadRight    = 0;
696     descriptor.m_PadTop      = 0;
697     descriptor.m_PadBottom   = 0;
698     descriptor.m_BiasEnabled = true;
699     descriptor.m_DataLayout  = armnn::DataLayout::NHWC;
700
701     armnn::INetworkPtr network = armnn::INetwork::Create();
702     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
703     armnn::IConnectableLayer* const convLayer   =
704         network->AddConvolution2dLayer(descriptor,
705                                        weights,
706                                        armnn::Optional<armnn::ConstTensor>(biases),
707                                        layerName.c_str());
708     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
709
710     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
711     convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
712
713     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
714     convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
715
716     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
717     BOOST_CHECK(deserializedNetwork);
718
719     Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
720     deserializedNetwork->Accept(verifier);
721 }
722
723 BOOST_AUTO_TEST_CASE(SerializeDepthToSpace)
724 {
725     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(DepthToSpace)
726
727     const std::string layerName("depthToSpace");
728
729     const armnn::TensorInfo inputInfo ({ 1,  8, 4, 12 }, armnn::DataType::Float32);
730     const armnn::TensorInfo outputInfo({ 1, 16, 8,  3 }, armnn::DataType::Float32);
731
732     armnn::DepthToSpaceDescriptor desc;
733     desc.m_BlockSize  = 2;
734     desc.m_DataLayout = armnn::DataLayout::NHWC;
735
736     armnn::INetworkPtr network = armnn::INetwork::Create();
737     armnn::IConnectableLayer* const inputLayer        = network->AddInputLayer(0);
738     armnn::IConnectableLayer* const depthToSpaceLayer = network->AddDepthToSpaceLayer(desc, layerName.c_str());
739     armnn::IConnectableLayer* const outputLayer       = network->AddOutputLayer(0);
740
741     inputLayer->GetOutputSlot(0).Connect(depthToSpaceLayer->GetInputSlot(0));
742     depthToSpaceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
743
744     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
745     depthToSpaceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
746
747     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
748     BOOST_CHECK(deserializedNetwork);
749
750     DepthToSpaceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
751     deserializedNetwork->Accept(verifier);
752 }
753
754 BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2d)
755 {
756     using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
757     class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
758     {
759     public:
760         DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
761                                             const std::vector<armnn::TensorInfo>& inputInfos,
762                                             const std::vector<armnn::TensorInfo>& outputInfos,
763                                             const Descriptor& descriptor,
764                                             const armnn::ConstTensor& weights,
765                                             const armnn::Optional<armnn::ConstTensor>& biases) :
766             LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
767             m_Weights(weights),
768             m_Biases(biases) {}
769
770         void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
771                                               const Descriptor& descriptor,
772                                               const armnn::ConstTensor& weights,
773                                               const armnn::Optional<armnn::ConstTensor>& biases,
774                                               const char* name) override
775         {
776             VerifyNameAndConnections(layer, name);
777             VerifyDescriptor(descriptor);
778
779             // check weights
780             CompareConstTensor(weights, m_Weights);
781
782             // check biases
783             BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
784             BOOST_CHECK(biases.has_value() == m_Biases.has_value());
785
786             if (biases.has_value() && m_Biases.has_value())
787             {
788                 CompareConstTensor(biases.value(), m_Biases.value());
789             }
790         }
791
792     private:
793         armnn::ConstTensor                      m_Weights;
794         armnn::Optional<armnn::ConstTensor>     m_Biases;
795     };
796
797     const std::string layerName("depwiseConvolution2d");
798     const armnn::TensorInfo inputInfo ({ 1, 5, 5, 3 }, armnn::DataType::Float32);
799     const armnn::TensorInfo outputInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
800
801     const armnn::TensorInfo weightsInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
802     const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
803
804     std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
805     armnn::ConstTensor weights(weightsInfo, weightsData);
806
807     std::vector<int32_t> biasesData = GenerateRandomData<int32_t>(biasesInfo.GetNumElements());
808     armnn::ConstTensor biases(biasesInfo, biasesData);
809
810     armnn::DepthwiseConvolution2dDescriptor descriptor;
811     descriptor.m_PadLeft     = 1;
812     descriptor.m_PadRight    = 1;
813     descriptor.m_PadTop      = 1;
814     descriptor.m_PadBottom   = 1;
815     descriptor.m_StrideX     = 2;
816     descriptor.m_StrideY     = 2;
817     descriptor.m_DilationX   = 2;
818     descriptor.m_DilationY   = 2;
819     descriptor.m_BiasEnabled = true;
820     descriptor.m_DataLayout  = armnn::DataLayout::NHWC;
821
822     armnn::INetworkPtr network = armnn::INetwork::Create();
823     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
824     armnn::IConnectableLayer* const depthwiseConvLayer =
825         network->AddDepthwiseConvolution2dLayer(descriptor,
826                                                 weights,
827                                                 armnn::Optional<armnn::ConstTensor>(biases),
828                                                 layerName.c_str());
829     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
830
831     inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
832     depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
833
834     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
835     depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
836
837     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
838     BOOST_CHECK(deserializedNetwork);
839
840     DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
841     deserializedNetwork->Accept(verifier);
842 }
843
844 BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2dWithPerAxisParams)
845 {
846     using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
847     class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
848     {
849     public:
850         DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
851                                             const std::vector<armnn::TensorInfo>& inputInfos,
852                                             const std::vector<armnn::TensorInfo>& outputInfos,
853                                             const Descriptor& descriptor,
854                                             const armnn::ConstTensor& weights,
855                                             const armnn::Optional<armnn::ConstTensor>& biases) :
856             LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
857             m_Weights(weights),
858             m_Biases(biases) {}
859
860         void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
861                                               const Descriptor& descriptor,
862                                               const armnn::ConstTensor& weights,
863                                               const armnn::Optional<armnn::ConstTensor>& biases,
864                                               const char* name) override
865         {
866             VerifyNameAndConnections(layer, name);
867             VerifyDescriptor(descriptor);
868
869             // check weights
870             CompareConstTensor(weights, m_Weights);
871
872             // check biases
873             BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
874             BOOST_CHECK(biases.has_value() == m_Biases.has_value());
875
876             if (biases.has_value() && m_Biases.has_value())
877             {
878                 CompareConstTensor(biases.value(), m_Biases.value());
879             }
880         }
881
882     private:
883         armnn::ConstTensor                      m_Weights;
884         armnn::Optional<armnn::ConstTensor>     m_Biases;
885     };
886
887     using namespace armnn;
888
889     const std::string layerName("depwiseConvolution2dWithPerAxis");
890     const TensorInfo inputInfo ({ 1, 3, 3, 2 }, DataType::QAsymmU8, 0.55f, 128);
891     const TensorInfo outputInfo({ 1, 2, 2, 4 }, DataType::QAsymmU8, 0.75f, 128);
892
893     const std::vector<float> quantScales{ 0.75f, 0.80f, 0.90f, 0.95f };
894     const unsigned int quantDimension = 0;
895     TensorInfo kernelInfo({ 2, 2, 2, 2 }, DataType::QSymmS8, quantScales, quantDimension);
896
897     const std::vector<float> biasQuantScales{ 0.25f, 0.35f, 0.45f, 0.55f };
898     constexpr unsigned int biasQuantDimension = 0;
899     TensorInfo biasInfo({ 4 }, DataType::Signed32, biasQuantScales, biasQuantDimension);
900
901     std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
902     armnn::ConstTensor weights(kernelInfo, kernelData);
903     std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
904     armnn::ConstTensor biases(biasInfo, biasData);
905
906     DepthwiseConvolution2dDescriptor descriptor;
907     descriptor.m_StrideX     = 1;
908     descriptor.m_StrideY     = 1;
909     descriptor.m_PadLeft     = 0;
910     descriptor.m_PadRight    = 0;
911     descriptor.m_PadTop      = 0;
912     descriptor.m_PadBottom   = 0;
913     descriptor.m_DilationX   = 1;
914     descriptor.m_DilationY   = 1;
915     descriptor.m_BiasEnabled = true;
916     descriptor.m_DataLayout  = armnn::DataLayout::NHWC;
917
918     armnn::INetworkPtr network = armnn::INetwork::Create();
919     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
920     armnn::IConnectableLayer* const depthwiseConvLayer =
921         network->AddDepthwiseConvolution2dLayer(descriptor,
922                                                 weights,
923                                                 armnn::Optional<armnn::ConstTensor>(biases),
924                                                 layerName.c_str());
925     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
926
927     inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
928     depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
929
930     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
931     depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
932
933     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
934     BOOST_CHECK(deserializedNetwork);
935
936     DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
937     deserializedNetwork->Accept(verifier);
938 }
939
940 BOOST_AUTO_TEST_CASE(SerializeDequantize)
941 {
942     DECLARE_LAYER_VERIFIER_CLASS(Dequantize)
943
944     const std::string layerName("dequantize");
945     const armnn::TensorInfo inputInfo({ 1, 5, 2, 3 }, armnn::DataType::QAsymmU8, 0.5f, 1);
946     const armnn::TensorInfo outputInfo({ 1, 5, 2, 3 }, armnn::DataType::Float32);
947
948     armnn::INetworkPtr network = armnn::INetwork::Create();
949     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
950     armnn::IConnectableLayer* const dequantizeLayer = network->AddDequantizeLayer(layerName.c_str());
951     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
952
953     inputLayer->GetOutputSlot(0).Connect(dequantizeLayer->GetInputSlot(0));
954     dequantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
955
956     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
957     dequantizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
958
959     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
960     BOOST_CHECK(deserializedNetwork);
961
962     DequantizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
963     deserializedNetwork->Accept(verifier);
964 }
965
966 BOOST_AUTO_TEST_CASE(SerializeDeserializeDetectionPostProcess)
967 {
968     using Descriptor = armnn::DetectionPostProcessDescriptor;
969     class DetectionPostProcessLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
970     {
971     public:
972         DetectionPostProcessLayerVerifier(const std::string& layerName,
973                                           const std::vector<armnn::TensorInfo>& inputInfos,
974                                           const std::vector<armnn::TensorInfo>& outputInfos,
975                                           const Descriptor& descriptor,
976                                           const armnn::ConstTensor& anchors)
977             : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
978             , m_Anchors(anchors) {}
979
980         void VisitDetectionPostProcessLayer(const armnn::IConnectableLayer* layer,
981                                             const Descriptor& descriptor,
982                                             const armnn::ConstTensor& anchors,
983                                             const char* name) override
984         {
985             VerifyNameAndConnections(layer, name);
986             VerifyDescriptor(descriptor);
987
988             CompareConstTensor(anchors, m_Anchors);
989         }
990
991     private:
992         armnn::ConstTensor m_Anchors;
993     };
994
995     const std::string layerName("detectionPostProcess");
996
997     const std::vector<armnn::TensorInfo> inputInfos({
998         armnn::TensorInfo({ 1, 6, 4 }, armnn::DataType::Float32),
999         armnn::TensorInfo({ 1, 6, 3}, armnn::DataType::Float32)
1000     });
1001
1002     const std::vector<armnn::TensorInfo> outputInfos({
1003         armnn::TensorInfo({ 1, 3, 4 }, armnn::DataType::Float32),
1004         armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1005         armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1006         armnn::TensorInfo({ 1 }, armnn::DataType::Float32)
1007     });
1008
1009     armnn::DetectionPostProcessDescriptor descriptor;
1010     descriptor.m_UseRegularNms = true;
1011     descriptor.m_MaxDetections = 3;
1012     descriptor.m_MaxClassesPerDetection = 1;
1013     descriptor.m_DetectionsPerClass =1;
1014     descriptor.m_NmsScoreThreshold = 0.0;
1015     descriptor.m_NmsIouThreshold = 0.5;
1016     descriptor.m_NumClasses = 2;
1017     descriptor.m_ScaleY = 10.0;
1018     descriptor.m_ScaleX = 10.0;
1019     descriptor.m_ScaleH = 5.0;
1020     descriptor.m_ScaleW = 5.0;
1021
1022     const armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32);
1023     const std::vector<float> anchorsData({
1024         0.5f, 0.5f, 1.0f, 1.0f,
1025         0.5f, 0.5f, 1.0f, 1.0f,
1026         0.5f, 0.5f, 1.0f, 1.0f,
1027         0.5f, 10.5f, 1.0f, 1.0f,
1028         0.5f, 10.5f, 1.0f, 1.0f,
1029         0.5f, 100.5f, 1.0f, 1.0f
1030     });
1031     armnn::ConstTensor anchors(anchorsInfo, anchorsData);
1032
1033     armnn::INetworkPtr network = armnn::INetwork::Create();
1034     armnn::IConnectableLayer* const detectionLayer =
1035         network->AddDetectionPostProcessLayer(descriptor, anchors, layerName.c_str());
1036
1037     for (unsigned int i = 0; i < 2; i++)
1038     {
1039         armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(static_cast<int>(i));
1040         inputLayer->GetOutputSlot(0).Connect(detectionLayer->GetInputSlot(i));
1041         inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfos[i]);
1042     }
1043
1044     for (unsigned int i = 0; i < 4; i++)
1045     {
1046         armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(static_cast<int>(i));
1047         detectionLayer->GetOutputSlot(i).Connect(outputLayer->GetInputSlot(0));
1048         detectionLayer->GetOutputSlot(i).SetTensorInfo(outputInfos[i]);
1049     }
1050
1051     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1052     BOOST_CHECK(deserializedNetwork);
1053
1054     DetectionPostProcessLayerVerifier verifier(layerName, inputInfos, outputInfos, descriptor, anchors);
1055     deserializedNetwork->Accept(verifier);
1056 }
1057
1058 BOOST_AUTO_TEST_CASE(SerializeDivision)
1059 {
1060     DECLARE_LAYER_VERIFIER_CLASS(Division)
1061
1062     const std::string layerName("division");
1063     const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1064
1065     armnn::INetworkPtr network = armnn::INetwork::Create();
1066     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1067     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1068     armnn::IConnectableLayer* const divisionLayer = network->AddDivisionLayer(layerName.c_str());
1069     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1070
1071     inputLayer0->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(0));
1072     inputLayer1->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(1));
1073     divisionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1074
1075     inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1076     inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1077     divisionLayer->GetOutputSlot(0).SetTensorInfo(info);
1078
1079     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1080     BOOST_CHECK(deserializedNetwork);
1081
1082     DivisionLayerVerifier verifier(layerName, {info, info}, {info});
1083     deserializedNetwork->Accept(verifier);
1084 }
1085
1086 class EqualLayerVerifier : public LayerVerifierBase
1087 {
1088 public:
1089     EqualLayerVerifier(const std::string& layerName,
1090                        const std::vector<armnn::TensorInfo>& inputInfos,
1091                        const std::vector<armnn::TensorInfo>& outputInfos)
1092         : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1093
1094     void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1095                               const armnn::ComparisonDescriptor& descriptor,
1096                               const char* name) override
1097     {
1098         VerifyNameAndConnections(layer, name);
1099         BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Equal);
1100     }
1101
1102     void VisitEqualLayer(const armnn::IConnectableLayer*, const char*) override
1103     {
1104         throw armnn::Exception("EqualLayer should have translated to ComparisonLayer");
1105     }
1106 };
1107
1108 // NOTE: Until the deprecated AddEqualLayer disappears this test checks that calling
1109 //       AddEqualLayer places a ComparisonLayer into the serialized format and that
1110 //       when this deserialises we have a ComparisonLayer
1111 BOOST_AUTO_TEST_CASE(SerializeEqual)
1112 {
1113     const std::string layerName("equal");
1114
1115     const armnn::TensorShape shape{2, 1, 2, 4};
1116
1117     const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Float32);
1118     const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1119
1120     armnn::INetworkPtr network = armnn::INetwork::Create();
1121     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1122     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1123     ARMNN_NO_DEPRECATE_WARN_BEGIN
1124     armnn::IConnectableLayer* const equalLayer = network->AddEqualLayer(layerName.c_str());
1125     ARMNN_NO_DEPRECATE_WARN_END
1126     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1127
1128     inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1129     inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1130     equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1131
1132     inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1133     inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1134     equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1135
1136     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1137     BOOST_CHECK(deserializedNetwork);
1138
1139     EqualLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1140     deserializedNetwork->Accept(verifier);
1141 }
1142
1143 BOOST_AUTO_TEST_CASE(EnsureEqualBackwardCompatibility)
1144 {
1145     // The hex data below is a flat buffer containing a simple network with two inputs,
1146     // an EqualLayer (now deprecated) and an output
1147     //
1148     // This test verifies that we can still deserialize this old-style model by replacing
1149     // the EqualLayer with an equivalent ComparisonLayer
1150     const std::vector<uint8_t> equalModel =
1151     {
1152         0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1153         0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1154         0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1155         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1156         0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1157         0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1158         0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1159         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1160         0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1161         0x00, 0x13, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1162         0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1163         0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1164         0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1165         0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1166         0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
1167         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1168         0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1169         0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1170         0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1171         0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1172         0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1173         0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1174         0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1175         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1176         0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1177         0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1178         0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
1179         0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1180         0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1181         0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1182         0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1183         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1184         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1185         0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1186         0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1187         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1188         0x04, 0x00, 0x00, 0x00
1189     };
1190
1191     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(equalModel.begin(), equalModel.end()));
1192     BOOST_CHECK(deserializedNetwork);
1193
1194     const armnn::TensorShape shape{ 2, 1, 2, 4 };
1195
1196     const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Float32);
1197     const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1198
1199     EqualLayerVerifier verifier("equal", { inputInfo, inputInfo }, { outputInfo });
1200     deserializedNetwork->Accept(verifier);
1201 }
1202
1203 BOOST_AUTO_TEST_CASE(SerializeFill)
1204 {
1205     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Fill)
1206
1207     const std::string layerName("fill");
1208     const armnn::TensorInfo inputInfo({4}, armnn::DataType::Signed32);
1209     const armnn::TensorInfo outputInfo({1, 3, 3, 1}, armnn::DataType::Float32);
1210
1211     armnn::FillDescriptor descriptor(1.0f);
1212
1213     armnn::INetworkPtr network = armnn::INetwork::Create();
1214     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1215     armnn::IConnectableLayer* const fillLayer = network->AddFillLayer(descriptor, layerName.c_str());
1216     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1217
1218     inputLayer->GetOutputSlot(0).Connect(fillLayer->GetInputSlot(0));
1219     fillLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1220
1221     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1222     fillLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1223
1224     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1225     BOOST_CHECK(deserializedNetwork);
1226
1227     FillLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1228
1229     deserializedNetwork->Accept(verifier);
1230 }
1231
1232 BOOST_AUTO_TEST_CASE(SerializeFloor)
1233 {
1234     DECLARE_LAYER_VERIFIER_CLASS(Floor)
1235
1236     const std::string layerName("floor");
1237     const armnn::TensorInfo info({4,4}, armnn::DataType::Float32);
1238
1239     armnn::INetworkPtr network = armnn::INetwork::Create();
1240     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1241     armnn::IConnectableLayer* const floorLayer = network->AddFloorLayer(layerName.c_str());
1242     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1243
1244     inputLayer->GetOutputSlot(0).Connect(floorLayer->GetInputSlot(0));
1245     floorLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1246
1247     inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1248     floorLayer->GetOutputSlot(0).SetTensorInfo(info);
1249
1250     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1251     BOOST_CHECK(deserializedNetwork);
1252
1253     FloorLayerVerifier verifier(layerName, {info}, {info});
1254     deserializedNetwork->Accept(verifier);
1255 }
1256
1257 BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
1258 {
1259     using Descriptor = armnn::FullyConnectedDescriptor;
1260     class FullyConnectedLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
1261     {
1262     public:
1263         FullyConnectedLayerVerifier(const std::string& layerName,
1264                                     const std::vector<armnn::TensorInfo>& inputInfos,
1265                                     const std::vector<armnn::TensorInfo>& outputInfos,
1266                                     const Descriptor& descriptor,
1267                                     const armnn::ConstTensor& weight,
1268                                     const armnn::Optional<armnn::ConstTensor>& bias)
1269             : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
1270             , m_Weight(weight)
1271             , m_Bias(bias) {}
1272
1273         void VisitFullyConnectedLayer(const armnn::IConnectableLayer* layer,
1274                                       const Descriptor& descriptor,
1275                                       const armnn::ConstTensor& weight,
1276                                       const armnn::Optional<armnn::ConstTensor>& bias,
1277                                       const char* name) override
1278         {
1279             VerifyNameAndConnections(layer, name);
1280             VerifyDescriptor(descriptor);
1281
1282             CompareConstTensor(weight, m_Weight);
1283
1284             BOOST_TEST(bias.has_value() == descriptor.m_BiasEnabled);
1285             BOOST_TEST(bias.has_value() == m_Bias.has_value());
1286
1287             if (bias.has_value() && m_Bias.has_value())
1288             {
1289                 CompareConstTensor(bias.value(), m_Bias.value());
1290             }
1291         }
1292
1293     private:
1294         armnn::ConstTensor m_Weight;
1295         armnn::Optional<armnn::ConstTensor> m_Bias;
1296     };
1297
1298     const std::string layerName("fullyConnected");
1299     const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
1300     const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
1301
1302     const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
1303     const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
1304     std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
1305     std::vector<float> biasesData  = GenerateRandomData<float>(biasesInfo.GetNumElements());
1306     armnn::ConstTensor weights(weightsInfo, weightsData);
1307     armnn::ConstTensor biases(biasesInfo, biasesData);
1308
1309     armnn::FullyConnectedDescriptor descriptor;
1310     descriptor.m_BiasEnabled = true;
1311     descriptor.m_TransposeWeightMatrix = false;
1312
1313     armnn::INetworkPtr network = armnn::INetwork::Create();
1314     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1315     armnn::IConnectableLayer* const fullyConnectedLayer =
1316         network->AddFullyConnectedLayer(descriptor,
1317                                         weights,
1318                                         armnn::Optional<armnn::ConstTensor>(biases),
1319                                         layerName.c_str());
1320     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1321
1322     inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
1323     fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1324
1325     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1326     fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1327
1328     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1329     BOOST_CHECK(deserializedNetwork);
1330
1331     FullyConnectedLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
1332     deserializedNetwork->Accept(verifier);
1333 }
1334
1335 BOOST_AUTO_TEST_CASE(SerializeGather)
1336 {
1337     using GatherDescriptor = armnn::GatherDescriptor;
1338     class GatherLayerVerifier : public LayerVerifierBaseWithDescriptor<GatherDescriptor>
1339     {
1340     public:
1341         GatherLayerVerifier(const std::string& layerName,
1342                             const std::vector<armnn::TensorInfo>& inputInfos,
1343                             const std::vector<armnn::TensorInfo>& outputInfos,
1344                             const GatherDescriptor& descriptor)
1345             : LayerVerifierBaseWithDescriptor<GatherDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
1346
1347         void VisitGatherLayer(const armnn::IConnectableLayer* layer,
1348                               const GatherDescriptor& descriptor,
1349                               const char *name) override
1350         {
1351             VerifyNameAndConnections(layer, name);
1352             BOOST_CHECK(descriptor.m_Axis == m_Descriptor.m_Axis);
1353         }
1354
1355         void VisitConstantLayer(const armnn::IConnectableLayer*,
1356                                 const armnn::ConstTensor&,
1357                                 const char*) override {}
1358     };
1359
1360     const std::string layerName("gather");
1361     armnn::TensorInfo paramsInfo({ 8 }, armnn::DataType::QAsymmU8);
1362     armnn::TensorInfo outputInfo({ 3 }, armnn::DataType::QAsymmU8);
1363     const armnn::TensorInfo indicesInfo({ 3 }, armnn::DataType::Signed32);
1364     GatherDescriptor descriptor;
1365     descriptor.m_Axis = 1;
1366
1367     paramsInfo.SetQuantizationScale(1.0f);
1368     paramsInfo.SetQuantizationOffset(0);
1369     outputInfo.SetQuantizationScale(1.0f);
1370     outputInfo.SetQuantizationOffset(0);
1371
1372     const std::vector<int32_t>& indicesData = {7, 6, 5};
1373
1374     armnn::INetworkPtr network = armnn::INetwork::Create();
1375     armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
1376     armnn::IConnectableLayer *const constantLayer =
1377             network->AddConstantLayer(armnn::ConstTensor(indicesInfo, indicesData));
1378     armnn::IConnectableLayer *const gatherLayer = network->AddGatherLayer(descriptor, layerName.c_str());
1379     armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
1380
1381     inputLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(0));
1382     constantLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(1));
1383     gatherLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1384
1385     inputLayer->GetOutputSlot(0).SetTensorInfo(paramsInfo);
1386     constantLayer->GetOutputSlot(0).SetTensorInfo(indicesInfo);
1387     gatherLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1388
1389     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1390     BOOST_CHECK(deserializedNetwork);
1391
1392     GatherLayerVerifier verifier(layerName, {paramsInfo, indicesInfo}, {outputInfo}, descriptor);
1393     deserializedNetwork->Accept(verifier);
1394 }
1395
1396 class GreaterLayerVerifier : public LayerVerifierBase
1397 {
1398 public:
1399     GreaterLayerVerifier(const std::string& layerName,
1400                          const std::vector<armnn::TensorInfo>& inputInfos,
1401                          const std::vector<armnn::TensorInfo>& outputInfos)
1402         : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1403
1404     void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1405                               const armnn::ComparisonDescriptor& descriptor,
1406                               const char* name) override
1407     {
1408         VerifyNameAndConnections(layer, name);
1409         BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Greater);
1410     }
1411
1412     void VisitGreaterLayer(const armnn::IConnectableLayer*, const char*) override
1413     {
1414         throw armnn::Exception("GreaterLayer should have translated to ComparisonLayer");
1415     }
1416 };
1417
1418 // NOTE: Until the deprecated AddGreaterLayer disappears this test checks that calling
1419 //       AddGreaterLayer places a ComparisonLayer into the serialized format and that
1420 //       when this deserialises we have a ComparisonLayer
1421 BOOST_AUTO_TEST_CASE(SerializeGreater)
1422 {
1423     const std::string layerName("greater");
1424
1425     const armnn::TensorShape shape{2, 1, 2, 4};
1426
1427     const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Float32);
1428     const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1429
1430     armnn::INetworkPtr network = armnn::INetwork::Create();
1431     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1432     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1433     ARMNN_NO_DEPRECATE_WARN_BEGIN
1434     armnn::IConnectableLayer* const equalLayer = network->AddGreaterLayer(layerName.c_str());
1435     ARMNN_NO_DEPRECATE_WARN_END
1436     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1437
1438     inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1439     inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1440     equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1441
1442     inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1443     inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1444     equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1445
1446     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1447     BOOST_CHECK(deserializedNetwork);
1448
1449     GreaterLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1450     deserializedNetwork->Accept(verifier);
1451 }
1452
1453 BOOST_AUTO_TEST_CASE(EnsureGreaterBackwardCompatibility)
1454 {
1455     // The hex data below is a flat buffer containing a simple network with two inputs,
1456     // an GreaterLayer (now deprecated) and an output
1457     //
1458     // This test verifies that we can still deserialize this old-style model by replacing
1459     // the GreaterLayer with an equivalent ComparisonLayer
1460     const std::vector<uint8_t> greaterModel =
1461     {
1462         0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1463         0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1464         0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1465         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1466         0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1467         0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1468         0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1469         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1470         0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1471         0x00, 0x19, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1472         0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1473         0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x00, 0x02, 0x00, 0x00, 0x00,
1474         0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1475         0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1476         0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1477         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1478         0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1479         0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1480         0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1481         0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1482         0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1483         0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1484         0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1485         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1486         0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1487         0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1488         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1489         0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1490         0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1491         0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1492         0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1493         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1494         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1495         0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1496         0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1497         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1498         0x02, 0x00, 0x00, 0x00
1499     };
1500
1501     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(greaterModel.begin(), greaterModel.end()));
1502     BOOST_CHECK(deserializedNetwork);
1503
1504     const armnn::TensorShape shape{ 1, 2, 2, 2 };
1505
1506     const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Float32);
1507     const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1508
1509     GreaterLayerVerifier verifier("greater", { inputInfo, inputInfo }, { outputInfo });
1510     deserializedNetwork->Accept(verifier);
1511 }
1512
1513 BOOST_AUTO_TEST_CASE(SerializeInstanceNormalization)
1514 {
1515     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(InstanceNormalization)
1516
1517     const std::string layerName("instanceNormalization");
1518     const armnn::TensorInfo info({ 1, 2, 1, 5 }, armnn::DataType::Float32);
1519
1520     armnn::InstanceNormalizationDescriptor descriptor;
1521     descriptor.m_Gamma      = 1.1f;
1522     descriptor.m_Beta       = 0.1f;
1523     descriptor.m_Eps        = 0.0001f;
1524     descriptor.m_DataLayout = armnn::DataLayout::NHWC;
1525
1526     armnn::INetworkPtr network = armnn::INetwork::Create();
1527     armnn::IConnectableLayer* const inputLayer        = network->AddInputLayer(0);
1528     armnn::IConnectableLayer* const instanceNormLayer =
1529         network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1530     armnn::IConnectableLayer* const outputLayer       = network->AddOutputLayer(0);
1531
1532     inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1533     instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1534
1535     inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1536     instanceNormLayer->GetOutputSlot(0).SetTensorInfo(info);
1537
1538     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1539     BOOST_CHECK(deserializedNetwork);
1540
1541     InstanceNormalizationLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1542     deserializedNetwork->Accept(verifier);
1543 }
1544
1545 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(L2Normalization)
1546
1547 BOOST_AUTO_TEST_CASE(SerializeL2Normalization)
1548 {
1549     const std::string l2NormLayerName("l2Normalization");
1550     const armnn::TensorInfo info({1, 2, 1, 5}, armnn::DataType::Float32);
1551
1552     armnn::L2NormalizationDescriptor desc;
1553     desc.m_DataLayout = armnn::DataLayout::NCHW;
1554     desc.m_Eps = 0.0001f;
1555
1556     armnn::INetworkPtr network = armnn::INetwork::Create();
1557     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1558     armnn::IConnectableLayer* const l2NormLayer = network->AddL2NormalizationLayer(desc, l2NormLayerName.c_str());
1559     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1560
1561     inputLayer0->GetOutputSlot(0).Connect(l2NormLayer->GetInputSlot(0));
1562     l2NormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1563
1564     inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1565     l2NormLayer->GetOutputSlot(0).SetTensorInfo(info);
1566
1567     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1568     BOOST_CHECK(deserializedNetwork);
1569
1570     L2NormalizationLayerVerifier verifier(l2NormLayerName, {info}, {info}, desc);
1571     deserializedNetwork->Accept(verifier);
1572 }
1573
1574 BOOST_AUTO_TEST_CASE(EnsureL2NormalizationBackwardCompatibility)
1575 {
1576     // The hex data below is a flat buffer containing a simple network with one input
1577     // a L2Normalization layer and an output layer with dimensions as per the tensor infos below.
1578     //
1579     // This test verifies that we can still read back these old style
1580     // models without the normalization epsilon value.
1581     const std::vector<uint8_t> l2NormalizationModel =
1582     {
1583         0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1584         0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1585         0x3C, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1586         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
1587         0x04, 0x00, 0x00, 0x00, 0xD6, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
1588         0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
1589         0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1590         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1591         0x4C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1592         0x00, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1593         0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1594         0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1595         0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x20, 0x00,
1596         0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x6C, 0x32, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x61, 0x74,
1597         0x69, 0x6F, 0x6E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00,
1598         0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1599         0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
1600         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1601         0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1602         0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1603         0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1604         0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1605         0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1606         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1607         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1608         0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1609         0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1610         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1611         0x05, 0x00, 0x00, 0x00, 0x00
1612     };
1613
1614     armnn::INetworkPtr deserializedNetwork =
1615         DeserializeNetwork(std::string(l2NormalizationModel.begin(), l2NormalizationModel.end()));
1616     BOOST_CHECK(deserializedNetwork);
1617
1618     const std::string layerName("l2Normalization");
1619     const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 2, 1, 5}, armnn::DataType::Float32);
1620
1621     armnn::L2NormalizationDescriptor desc;
1622     desc.m_DataLayout = armnn::DataLayout::NCHW;
1623     // Since this variable does not exist in the l2NormalizationModel dump, the default value will be loaded
1624     desc.m_Eps = 1e-12f;
1625
1626     L2NormalizationLayerVerifier verifier(layerName, {inputInfo}, {inputInfo}, desc);
1627     deserializedNetwork->Accept(verifier);
1628 }
1629
1630 BOOST_AUTO_TEST_CASE(SerializeLogicalBinary)
1631 {
1632     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(LogicalBinary)
1633
1634     const std::string layerName("logicalBinaryAnd");
1635
1636     const armnn::TensorShape shape{2, 1, 2, 2};
1637
1638     const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1639     const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1640
1641     armnn::LogicalBinaryDescriptor descriptor(armnn::LogicalBinaryOperation::LogicalAnd);
1642
1643     armnn::INetworkPtr network = armnn::INetwork::Create();
1644     armnn::IConnectableLayer* const inputLayer0        = network->AddInputLayer(0);
1645     armnn::IConnectableLayer* const inputLayer1        = network->AddInputLayer(1);
1646     armnn::IConnectableLayer* const logicalBinaryLayer = network->AddLogicalBinaryLayer(descriptor, layerName.c_str());
1647     armnn::IConnectableLayer* const outputLayer        = network->AddOutputLayer(0);
1648
1649     inputLayer0->GetOutputSlot(0).Connect(logicalBinaryLayer->GetInputSlot(0));
1650     inputLayer1->GetOutputSlot(0).Connect(logicalBinaryLayer->GetInputSlot(1));
1651     logicalBinaryLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1652
1653     inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1654     inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1655     logicalBinaryLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1656
1657     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1658     BOOST_CHECK(deserializedNetwork);
1659
1660     LogicalBinaryLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo }, descriptor);
1661     deserializedNetwork->Accept(verifier);
1662 }
1663
1664 BOOST_AUTO_TEST_CASE(SerializeLogicalUnary)
1665 {
1666     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(ElementwiseUnary)
1667
1668     const std::string layerName("elementwiseUnaryLogicalNot");
1669
1670     const armnn::TensorShape shape{2, 1, 2, 2};
1671
1672     const armnn::TensorInfo inputInfo  = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1673     const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1674
1675     armnn::ElementwiseUnaryDescriptor descriptor(armnn::UnaryOperation::LogicalNot);
1676
1677     armnn::INetworkPtr network = armnn::INetwork::Create();
1678     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1679     armnn::IConnectableLayer* const elementwiseUnaryLayer =
1680         network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
1681     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1682
1683     inputLayer->GetOutputSlot(0).Connect(elementwiseUnaryLayer->GetInputSlot(0));
1684     elementwiseUnaryLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1685
1686     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1687     elementwiseUnaryLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1688
1689     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1690
1691     BOOST_CHECK(deserializedNetwork);
1692
1693     ElementwiseUnaryLayerVerifier verifier(layerName, { inputInfo }, { outputInfo }, descriptor);
1694
1695     deserializedNetwork->Accept(verifier);
1696 }
1697
1698 BOOST_AUTO_TEST_CASE(SerializeLogSoftmax)
1699 {
1700     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(LogSoftmax)
1701
1702     const std::string layerName("log_softmax");
1703     const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
1704
1705     armnn::LogSoftmaxDescriptor descriptor;
1706     descriptor.m_Beta = 1.0f;
1707     descriptor.m_Axis = -1;
1708
1709     armnn::INetworkPtr network = armnn::INetwork::Create();
1710     armnn::IConnectableLayer* const inputLayer      = network->AddInputLayer(0);
1711     armnn::IConnectableLayer* const logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
1712     armnn::IConnectableLayer* const outputLayer     = network->AddOutputLayer(0);
1713
1714     inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
1715     logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1716
1717     inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1718     logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
1719
1720     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1721     BOOST_CHECK(deserializedNetwork);
1722
1723     LogSoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1724     deserializedNetwork->Accept(verifier);
1725 }
1726
1727 BOOST_AUTO_TEST_CASE(SerializeMaximum)
1728 {
1729     DECLARE_LAYER_VERIFIER_CLASS(Maximum)
1730
1731     const std::string layerName("maximum");
1732     const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1733
1734     armnn::INetworkPtr network = armnn::INetwork::Create();
1735     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1736     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1737     armnn::IConnectableLayer* const maximumLayer = network->AddMaximumLayer(layerName.c_str());
1738     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1739
1740     inputLayer0->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(0));
1741     inputLayer1->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(1));
1742     maximumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1743
1744     inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1745     inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1746     maximumLayer->GetOutputSlot(0).SetTensorInfo(info);
1747
1748     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1749     BOOST_CHECK(deserializedNetwork);
1750
1751     MaximumLayerVerifier verifier(layerName, {info, info}, {info});
1752     deserializedNetwork->Accept(verifier);
1753 }
1754
1755 BOOST_AUTO_TEST_CASE(SerializeMean)
1756 {
1757     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Mean)
1758
1759     const std::string layerName("mean");
1760     const armnn::TensorInfo inputInfo({1, 1, 3, 2}, armnn::DataType::Float32);
1761     const armnn::TensorInfo outputInfo({1, 1, 1, 2}, armnn::DataType::Float32);
1762
1763     armnn::MeanDescriptor descriptor;
1764     descriptor.m_Axis = { 2 };
1765     descriptor.m_KeepDims = true;
1766
1767     armnn::INetworkPtr network = armnn::INetwork::Create();
1768     armnn::IConnectableLayer* const inputLayer   = network->AddInputLayer(0);
1769     armnn::IConnectableLayer* const meanLayer = network->AddMeanLayer(descriptor, layerName.c_str());
1770     armnn::IConnectableLayer* const outputLayer  = network->AddOutputLayer(0);
1771
1772     inputLayer->GetOutputSlot(0).Connect(meanLayer->GetInputSlot(0));
1773     meanLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1774
1775     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1776     meanLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1777
1778     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1779     BOOST_CHECK(deserializedNetwork);
1780
1781     MeanLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1782     deserializedNetwork->Accept(verifier);
1783 }
1784
1785 BOOST_AUTO_TEST_CASE(SerializeMerge)
1786 {
1787     DECLARE_LAYER_VERIFIER_CLASS(Merge)
1788
1789     const std::string layerName("merge");
1790     const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1791
1792     armnn::INetworkPtr network = armnn::INetwork::Create();
1793     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1794     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1795     armnn::IConnectableLayer* const mergeLayer = network->AddMergeLayer(layerName.c_str());
1796     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1797
1798     inputLayer0->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(0));
1799     inputLayer1->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(1));
1800     mergeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1801
1802     inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1803     inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1804     mergeLayer->GetOutputSlot(0).SetTensorInfo(info);
1805
1806     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1807     BOOST_CHECK(deserializedNetwork);
1808
1809     MergeLayerVerifier verifier(layerName, {info, info}, {info});
1810     deserializedNetwork->Accept(verifier);
1811 }
1812
1813 class MergerLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>
1814 {
1815 public:
1816     MergerLayerVerifier(const std::string& layerName,
1817                         const std::vector<armnn::TensorInfo>& inputInfos,
1818                         const std::vector<armnn::TensorInfo>& outputInfos,
1819                         const armnn::OriginsDescriptor& descriptor)
1820         : LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
1821
1822     void VisitMergerLayer(const armnn::IConnectableLayer*,
1823                           const armnn::OriginsDescriptor&,
1824                           const char*) override
1825     {
1826         throw armnn::Exception("MergerLayer should have translated to ConcatLayer");
1827     }
1828
1829     void VisitConcatLayer(const armnn::IConnectableLayer* layer,
1830                           const armnn::OriginsDescriptor& descriptor,
1831                           const char* name) override
1832     {
1833         VerifyNameAndConnections(layer, name);
1834         VerifyDescriptor(descriptor);
1835     }
1836 };
1837
1838 // NOTE: Until the deprecated AddMergerLayer disappears this test checks that calling
1839 //       AddMergerLayer places a ConcatLayer into the serialized format and that
1840 //       when this deserialises we have a ConcatLayer
1841 BOOST_AUTO_TEST_CASE(SerializeMerger)
1842 {
1843     const std::string layerName("merger");
1844     const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1845     const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1846
1847     const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1848
1849     armnn::OriginsDescriptor descriptor =
1850         armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1851
1852     armnn::INetworkPtr network = armnn::INetwork::Create();
1853     armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1854     armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1855     ARMNN_NO_DEPRECATE_WARN_BEGIN
1856     armnn::IConnectableLayer* const mergerLayer = network->AddMergerLayer(descriptor, layerName.c_str());
1857     ARMNN_NO_DEPRECATE_WARN_END
1858     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1859
1860     inputLayerOne->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0));
1861     inputLayerTwo->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1));
1862     mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1863
1864     inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1865     inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1866     mergerLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1867
1868     std::string mergerLayerNetwork = SerializeNetwork(*network);
1869     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(mergerLayerNetwork);
1870     BOOST_CHECK(deserializedNetwork);
1871
1872     MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1873     deserializedNetwork->Accept(verifier);
1874 }
1875
1876 BOOST_AUTO_TEST_CASE(EnsureMergerLayerBackwardCompatibility)
1877 {
1878     // The hex data below is a flat buffer containing a simple network with two inputs
1879     // a merger layer (now deprecated) and an output layer with dimensions as per the tensor infos below.
1880     //
1881     // This test verifies that we can still read back these old style
1882     // models replacing the MergerLayers with ConcatLayers with the same parameters.
1883     const std::vector<uint8_t> mergerModel =
1884     {
1885         0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1886         0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1887         0x38, 0x02, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1888         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1889         0xF4, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1890         0x00, 0x00, 0x9A, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1891         0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1892         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1893         0xF8, 0xFE, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1894         0x00, 0x1F, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1895         0x68, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
1896         0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1897         0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
1898         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1899         0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1900         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1901         0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1902         0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x72, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1903         0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1904         0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
1905         0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00,
1906         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1907         0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1908         0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1909         0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1910         0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1911         0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1912         0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1913         0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1914         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1915         0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1916         0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1917         0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1918         0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1919         0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1920         0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1921         0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1922         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1923         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1924         0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1925         0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1926         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1927         0x02, 0x00, 0x00, 0x00
1928     };
1929
1930     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(mergerModel.begin(), mergerModel.end()));
1931     BOOST_CHECK(deserializedNetwork);
1932
1933     const armnn::TensorInfo inputInfo  = armnn::TensorInfo({ 2, 3, 2, 2 }, armnn::DataType::Float32);
1934     const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 4, 3, 2, 2 }, armnn::DataType::Float32);
1935
1936     const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1937
1938     armnn::OriginsDescriptor descriptor =
1939             armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1940
1941     MergerLayerVerifier verifier("merger", { inputInfo, inputInfo }, { outputInfo }, descriptor);
1942     deserializedNetwork->Accept(verifier);
1943 }
1944
1945 BOOST_AUTO_TEST_CASE(SerializeConcat)
1946 {
1947     const std::string layerName("concat");
1948     const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1949     const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1950
1951     const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1952
1953     armnn::OriginsDescriptor descriptor =
1954         armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1955
1956     armnn::INetworkPtr network = armnn::INetwork::Create();
1957     armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1958     armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1959     armnn::IConnectableLayer* const concatLayer = network->AddConcatLayer(descriptor, layerName.c_str());
1960     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1961
1962     inputLayerOne->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
1963     inputLayerTwo->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
1964     concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1965
1966     inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1967     inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1968     concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1969
1970     std::string concatLayerNetwork = SerializeNetwork(*network);
1971     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(concatLayerNetwork);
1972     BOOST_CHECK(deserializedNetwork);
1973
1974     // NOTE: using the MergerLayerVerifier to ensure that it is a concat layer and not a
1975     //       merger layer that gets placed into the graph.
1976     MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1977     deserializedNetwork->Accept(verifier);
1978 }
1979
1980 BOOST_AUTO_TEST_CASE(SerializeMinimum)
1981 {
1982     DECLARE_LAYER_VERIFIER_CLASS(Minimum)
1983
1984     const std::string layerName("minimum");
1985     const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1986
1987     armnn::INetworkPtr network = armnn::INetwork::Create();
1988     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1989     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1990     armnn::IConnectableLayer* const minimumLayer = network->AddMinimumLayer(layerName.c_str());
1991     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1992
1993     inputLayer0->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(0));
1994     inputLayer1->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(1));
1995     minimumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1996
1997     inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1998     inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1999     minimumLayer->GetOutputSlot(0).SetTensorInfo(info);
2000
2001     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2002     BOOST_CHECK(deserializedNetwork);
2003
2004     MinimumLayerVerifier verifier(layerName, {info, info}, {info});
2005     deserializedNetwork->Accept(verifier);
2006 }
2007
2008 BOOST_AUTO_TEST_CASE(SerializeMultiplication)
2009 {
2010     DECLARE_LAYER_VERIFIER_CLASS(Multiplication)
2011
2012     const std::string layerName("multiplication");
2013     const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
2014
2015     armnn::INetworkPtr network = armnn::INetwork::Create();
2016     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2017     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2018     armnn::IConnectableLayer* const multiplicationLayer = network->AddMultiplicationLayer(layerName.c_str());
2019     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2020
2021     inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(0));
2022     inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(1));
2023     multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2024
2025     inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2026     inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2027     multiplicationLayer->GetOutputSlot(0).SetTensorInfo(info);
2028
2029     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2030     BOOST_CHECK(deserializedNetwork);
2031
2032     MultiplicationLayerVerifier verifier(layerName, {info, info}, {info});
2033     deserializedNetwork->Accept(verifier);
2034 }
2035
2036 BOOST_AUTO_TEST_CASE(SerializePrelu)
2037 {
2038     DECLARE_LAYER_VERIFIER_CLASS(Prelu)
2039
2040     const std::string layerName("prelu");
2041
2042     armnn::TensorInfo inputTensorInfo ({ 4, 1, 2 }, armnn::DataType::Float32);
2043     armnn::TensorInfo alphaTensorInfo ({ 5, 4, 3, 1 }, armnn::DataType::Float32);
2044     armnn::TensorInfo outputTensorInfo({ 5, 4, 3, 2 }, armnn::DataType::Float32);
2045
2046     armnn::INetworkPtr network = armnn::INetwork::Create();
2047     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2048     armnn::IConnectableLayer* const alphaLayer = network->AddInputLayer(1);
2049     armnn::IConnectableLayer* const preluLayer = network->AddPreluLayer(layerName.c_str());
2050     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2051
2052     inputLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(0));
2053     alphaLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(1));
2054     preluLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2055
2056     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2057     alphaLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2058     preluLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2059
2060     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2061     BOOST_CHECK(deserializedNetwork);
2062
2063     PreluLayerVerifier verifier(layerName, {inputTensorInfo, alphaTensorInfo}, {outputTensorInfo});
2064     deserializedNetwork->Accept(verifier);
2065 }
2066
2067 BOOST_AUTO_TEST_CASE(SerializeNormalization)
2068 {
2069     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Normalization)
2070
2071     const std::string layerName("normalization");
2072     const armnn::TensorInfo info({2, 1, 2, 2}, armnn::DataType::Float32);
2073
2074     armnn::NormalizationDescriptor desc;
2075     desc.m_DataLayout = armnn::DataLayout::NCHW;
2076     desc.m_NormSize = 3;
2077     desc.m_Alpha = 1;
2078     desc.m_Beta = 1;
2079     desc.m_K = 1;
2080
2081     armnn::INetworkPtr network = armnn::INetwork::Create();
2082     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2083     armnn::IConnectableLayer* const normalizationLayer = network->AddNormalizationLayer(desc, layerName.c_str());
2084     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2085
2086     inputLayer->GetOutputSlot(0).Connect(normalizationLayer->GetInputSlot(0));
2087     normalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2088
2089     inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2090     normalizationLayer->GetOutputSlot(0).SetTensorInfo(info);
2091
2092     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2093     BOOST_CHECK(deserializedNetwork);
2094
2095     NormalizationLayerVerifier verifier(layerName, {info}, {info}, desc);
2096     deserializedNetwork->Accept(verifier);
2097 }
2098
2099 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pad)
2100
2101 BOOST_AUTO_TEST_CASE(SerializePad)
2102 {
2103     const std::string layerName("pad");
2104     const armnn::TensorInfo inputTensorInfo = armnn::TensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2105     const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({1, 3, 5, 7}, armnn::DataType::Float32);
2106
2107     armnn::PadDescriptor desc({{0, 0}, {1, 0}, {1, 1}, {1, 2}});
2108
2109     armnn::INetworkPtr network = armnn::INetwork::Create();
2110     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2111     armnn::IConnectableLayer* const padLayer = network->AddPadLayer(desc, layerName.c_str());
2112     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2113
2114     inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
2115     padLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2116
2117     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2118     padLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2119
2120     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2121     BOOST_CHECK(deserializedNetwork);
2122
2123     PadLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, desc);
2124     deserializedNetwork->Accept(verifier);
2125 }
2126
2127 BOOST_AUTO_TEST_CASE(EnsurePadBackwardCompatibility)
2128 {
2129     // The PadDescriptor is being extended with a float PadValue (so a value other than 0
2130     // can be used to pad the tensor.
2131     //
2132     // This test contains a binary representation of a simple input->pad->output network
2133     // prior to this change to test that the descriptor has been updated in a backward
2134     // compatible way with respect to Deserialization of older binary dumps
2135     const std::vector<uint8_t> padModel =
2136     {
2137         0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2138         0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2139         0x54, 0x01, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2140         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD0, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2141         0x04, 0x00, 0x00, 0x00, 0x96, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
2142         0x00, 0x00, 0x72, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2143         0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
2144         0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
2145         0x00, 0x00, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x16, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00,
2146         0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2147         0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00,
2148         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2149         0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
2150         0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
2151         0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00,
2152         0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
2153         0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
2154         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2155         0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2156         0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
2157         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00,
2158         0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00,
2159         0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2160         0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00,
2161         0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2162         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2163         0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2164         0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
2165         0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
2166         0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00
2167     };
2168
2169     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(padModel.begin(), padModel.end()));
2170     BOOST_CHECK(deserializedNetwork);
2171
2172     const armnn::TensorInfo inputInfo  = armnn::TensorInfo({ 1, 2, 3, 4 }, armnn::DataType::Float32);
2173     const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 1, 3, 5, 7 }, armnn::DataType::Float32);
2174
2175     armnn::PadDescriptor descriptor({{ 0, 0 }, { 1, 0 }, { 1, 1 }, { 1, 2 }});
2176
2177     PadLayerVerifier verifier("pad", { inputInfo }, { outputInfo }, descriptor);
2178     deserializedNetwork->Accept(verifier);
2179 }
2180
2181 BOOST_AUTO_TEST_CASE(SerializePermute)
2182 {
2183     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Permute)
2184
2185     const std::string layerName("permute");
2186     const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2187     const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2188
2189     armnn::PermuteDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2190
2191     armnn::INetworkPtr network = armnn::INetwork::Create();
2192     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2193     armnn::IConnectableLayer* const permuteLayer = network->AddPermuteLayer(descriptor, layerName.c_str());
2194     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2195
2196     inputLayer->GetOutputSlot(0).Connect(permuteLayer->GetInputSlot(0));
2197     permuteLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2198
2199     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2200     permuteLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2201
2202     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2203     BOOST_CHECK(deserializedNetwork);
2204
2205     PermuteLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2206     deserializedNetwork->Accept(verifier);
2207 }
2208
2209 BOOST_AUTO_TEST_CASE(SerializePooling2d)
2210 {
2211     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pooling2d)
2212
2213     const std::string layerName("pooling2d");
2214     const armnn::TensorInfo inputInfo({1, 2, 2, 1}, armnn::DataType::Float32);
2215     const armnn::TensorInfo outputInfo({1, 1, 1, 1}, armnn::DataType::Float32);
2216
2217     armnn::Pooling2dDescriptor desc;
2218     desc.m_DataLayout          = armnn::DataLayout::NHWC;
2219     desc.m_PadTop              = 0;
2220     desc.m_PadBottom           = 0;
2221     desc.m_PadLeft             = 0;
2222     desc.m_PadRight            = 0;
2223     desc.m_PoolType            = armnn::PoolingAlgorithm::Average;
2224     desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
2225     desc.m_PaddingMethod       = armnn::PaddingMethod::Exclude;
2226     desc.m_PoolHeight          = 2;
2227     desc.m_PoolWidth           = 2;
2228     desc.m_StrideX             = 2;
2229     desc.m_StrideY             = 2;
2230
2231     armnn::INetworkPtr network = armnn::INetwork::Create();
2232     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2233     armnn::IConnectableLayer* const pooling2dLayer = network->AddPooling2dLayer(desc, layerName.c_str());
2234     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2235
2236     inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0));
2237     pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2238
2239     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2240     pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2241
2242     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2243     BOOST_CHECK(deserializedNetwork);
2244
2245     Pooling2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2246     deserializedNetwork->Accept(verifier);
2247 }
2248
2249 BOOST_AUTO_TEST_CASE(SerializeQuantize)
2250 {
2251     DECLARE_LAYER_VERIFIER_CLASS(Quantize)
2252
2253     const std::string layerName("quantize");
2254     const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
2255
2256     armnn::INetworkPtr network = armnn::INetwork::Create();
2257     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2258     armnn::IConnectableLayer* const quantizeLayer = network->AddQuantizeLayer(layerName.c_str());
2259     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2260
2261     inputLayer->GetOutputSlot(0).Connect(quantizeLayer->GetInputSlot(0));
2262     quantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2263
2264     inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2265     quantizeLayer->GetOutputSlot(0).SetTensorInfo(info);
2266
2267     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2268     BOOST_CHECK(deserializedNetwork);
2269
2270     QuantizeLayerVerifier verifier(layerName, {info}, {info});
2271     deserializedNetwork->Accept(verifier);
2272 }
2273
2274 BOOST_AUTO_TEST_CASE(SerializeRank)
2275 {
2276     DECLARE_LAYER_VERIFIER_CLASS(Rank)
2277
2278     const std::string layerName("rank");
2279     const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2280     const armnn::TensorInfo outputInfo({1}, armnn::DataType::Signed32);
2281
2282     armnn::INetworkPtr network = armnn::INetwork::Create();
2283     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2284     armnn::IConnectableLayer* const rankLayer = network->AddRankLayer(layerName.c_str());
2285     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2286
2287     inputLayer->GetOutputSlot(0).Connect(rankLayer->GetInputSlot(0));
2288     rankLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2289
2290     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2291     rankLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2292
2293     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2294     BOOST_CHECK(deserializedNetwork);
2295
2296     RankLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
2297     deserializedNetwork->Accept(verifier);
2298 }
2299
2300 BOOST_AUTO_TEST_CASE(SerializeReshape)
2301 {
2302     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Reshape)
2303
2304     const std::string layerName("reshape");
2305     const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2306     const armnn::TensorInfo outputInfo({3, 3}, armnn::DataType::Float32);
2307
2308     armnn::ReshapeDescriptor descriptor({3, 3});
2309
2310     armnn::INetworkPtr network = armnn::INetwork::Create();
2311     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2312     armnn::IConnectableLayer* const reshapeLayer = network->AddReshapeLayer(descriptor, layerName.c_str());
2313     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2314
2315     inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0));
2316     reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2317
2318     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2319     reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2320
2321     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2322     BOOST_CHECK(deserializedNetwork);
2323
2324     ReshapeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2325     deserializedNetwork->Accept(verifier);
2326 }
2327
2328 BOOST_AUTO_TEST_CASE(SerializeResize)
2329 {
2330     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Resize)
2331
2332     const std::string layerName("resize");
2333     const armnn::TensorInfo inputInfo  = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2334     const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2335
2336     armnn::ResizeDescriptor desc;
2337     desc.m_TargetWidth  = 4;
2338     desc.m_TargetHeight = 2;
2339     desc.m_Method       = armnn::ResizeMethod::NearestNeighbor;
2340     desc.m_AlignCorners = true;
2341     desc.m_HalfPixelCenters = true;
2342
2343     armnn::INetworkPtr network = armnn::INetwork::Create();
2344     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2345     armnn::IConnectableLayer* const resizeLayer = network->AddResizeLayer(desc, layerName.c_str());
2346     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2347
2348     inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2349     resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2350
2351     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2352     resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2353
2354     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2355     BOOST_CHECK(deserializedNetwork);
2356
2357     ResizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2358     deserializedNetwork->Accept(verifier);
2359 }
2360
2361 class ResizeBilinearLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>
2362 {
2363 public:
2364     ResizeBilinearLayerVerifier(const std::string& layerName,
2365                                 const std::vector<armnn::TensorInfo>& inputInfos,
2366                                 const std::vector<armnn::TensorInfo>& outputInfos,
2367                                 const armnn::ResizeBilinearDescriptor& descriptor)
2368         : LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>(
2369             layerName, inputInfos, outputInfos, descriptor) {}
2370
2371     void VisitResizeLayer(const armnn::IConnectableLayer* layer,
2372                           const armnn::ResizeDescriptor& descriptor,
2373                           const char* name) override
2374     {
2375         VerifyNameAndConnections(layer, name);
2376
2377         BOOST_CHECK(descriptor.m_Method             == armnn::ResizeMethod::Bilinear);
2378         BOOST_CHECK(descriptor.m_TargetWidth        == m_Descriptor.m_TargetWidth);
2379         BOOST_CHECK(descriptor.m_TargetHeight       == m_Descriptor.m_TargetHeight);
2380         BOOST_CHECK(descriptor.m_DataLayout         == m_Descriptor.m_DataLayout);
2381         BOOST_CHECK(descriptor.m_AlignCorners       == m_Descriptor.m_AlignCorners);
2382         BOOST_CHECK(descriptor.m_HalfPixelCenters   == m_Descriptor.m_HalfPixelCenters);
2383     }
2384
2385     void VisitResizeBilinearLayer(const armnn::IConnectableLayer*,
2386                                   const armnn::ResizeBilinearDescriptor&,
2387                                   const char*) override
2388     {
2389         throw armnn::Exception("ResizeBilinearLayer should have translated to ResizeLayer");
2390     }
2391 };
2392
2393 // NOTE: Until the deprecated AddResizeBilinearLayer disappears this test checks that
2394 //       calling AddResizeBilinearLayer places a ResizeLayer into the serialized format
2395 //       and that when this deserialises we have a ResizeLayer
2396 BOOST_AUTO_TEST_CASE(SerializeResizeBilinear)
2397 {
2398     const std::string layerName("resizeBilinear");
2399     const armnn::TensorInfo inputInfo  = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2400     const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2401
2402     armnn::ResizeBilinearDescriptor desc;
2403     desc.m_TargetWidth  = 4u;
2404     desc.m_TargetHeight = 2u;
2405     desc.m_AlignCorners = true;
2406     desc.m_HalfPixelCenters = true;
2407
2408     armnn::INetworkPtr network = armnn::INetwork::Create();
2409     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2410     ARMNN_NO_DEPRECATE_WARN_BEGIN
2411     armnn::IConnectableLayer* const resizeLayer = network->AddResizeBilinearLayer(desc, layerName.c_str());
2412     ARMNN_NO_DEPRECATE_WARN_END
2413     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2414
2415     inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2416     resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2417
2418     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2419     resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2420
2421     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2422     BOOST_CHECK(deserializedNetwork);
2423
2424     ResizeBilinearLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2425     deserializedNetwork->Accept(verifier);
2426 }
2427
2428 BOOST_AUTO_TEST_CASE(EnsureResizeBilinearBackwardCompatibility)
2429 {
2430     // The hex data below is a flat buffer containing a simple network with an input,
2431     // a ResizeBilinearLayer (now deprecated) and an output
2432     //
2433     // This test verifies that we can still deserialize this old-style model by replacing
2434     // the ResizeBilinearLayer with an equivalent ResizeLayer
2435     const std::vector<uint8_t> resizeBilinearModel =
2436     {
2437         0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2438         0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2439         0x50, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2440         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD4, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2441         0x04, 0x00, 0x00, 0x00, 0xC2, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
2442         0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8A, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
2443         0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2444         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2445         0x38, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
2446         0x00, 0x1A, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
2447         0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x08, 0x00, 0x0C, 0x00,
2448         0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
2449         0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00,
2450         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
2451         0x20, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x42, 0x69, 0x6C, 0x69,
2452         0x6E, 0x65, 0x61, 0x72, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2453         0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
2454         0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2455         0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
2456         0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2457         0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
2458         0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
2459         0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00,
2460         0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
2461         0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2462         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00,
2463         0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00,
2464         0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2465         0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2466         0x00, 0x00, 0x05, 0x00, 0x00, 0x00
2467     };
2468
2469     armnn::INetworkPtr deserializedNetwork =
2470         DeserializeNetwork(std::string(resizeBilinearModel.begin(), resizeBilinearModel.end()));
2471     BOOST_CHECK(deserializedNetwork);
2472
2473     const armnn::TensorInfo inputInfo  = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2474     const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2475
2476     armnn::ResizeBilinearDescriptor descriptor;
2477     descriptor.m_TargetWidth  = 4u;
2478     descriptor.m_TargetHeight = 2u;
2479
2480     ResizeBilinearLayerVerifier verifier("resizeBilinear", { inputInfo }, { outputInfo }, descriptor);
2481     deserializedNetwork->Accept(verifier);
2482 }
2483
2484 BOOST_AUTO_TEST_CASE(SerializeSlice)
2485 {
2486     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Slice)
2487
2488     const std::string layerName{"slice"};
2489
2490     const armnn::TensorInfo inputInfo  = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2491     const armnn::TensorInfo outputInfo = armnn::TensorInfo({2, 2, 2, 1}, armnn::DataType::Float32);
2492
2493     armnn::SliceDescriptor descriptor({ 0, 0, 1, 0}, {2, 2, 2, 1});
2494
2495     armnn::INetworkPtr network = armnn::INetwork::Create();
2496
2497     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
2498     armnn::IConnectableLayer* const sliceLayer  = network->AddSliceLayer(descriptor, layerName.c_str());
2499     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2500
2501     inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
2502     sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2503
2504     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2505     sliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2506
2507     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2508     BOOST_CHECK(deserializedNetwork);
2509
2510     SliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2511     deserializedNetwork->Accept(verifier);
2512 }
2513
2514 BOOST_AUTO_TEST_CASE(SerializeSoftmax)
2515 {
2516     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Softmax)
2517
2518     const std::string layerName("softmax");
2519     const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
2520
2521     armnn::SoftmaxDescriptor descriptor;
2522     descriptor.m_Beta = 1.0f;
2523
2524     armnn::INetworkPtr network = armnn::INetwork::Create();
2525     armnn::IConnectableLayer* const inputLayer   = network->AddInputLayer(0);
2526     armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, layerName.c_str());
2527     armnn::IConnectableLayer* const outputLayer  = network->AddOutputLayer(0);
2528
2529     inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
2530     softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2531
2532     inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2533     softmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
2534
2535     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2536     BOOST_CHECK(deserializedNetwork);
2537
2538     SoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
2539     deserializedNetwork->Accept(verifier);
2540 }
2541
2542 BOOST_AUTO_TEST_CASE(SerializeSpaceToBatchNd)
2543 {
2544     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToBatchNd)
2545
2546     const std::string layerName("spaceToBatchNd");
2547     const armnn::TensorInfo inputInfo({2, 1, 2, 4}, armnn::DataType::Float32);
2548     const armnn::TensorInfo outputInfo({8, 1, 1, 3}, armnn::DataType::Float32);
2549
2550     armnn::SpaceToBatchNdDescriptor desc;
2551     desc.m_DataLayout = armnn::DataLayout::NCHW;
2552     desc.m_BlockShape = {2, 2};
2553     desc.m_PadList = {{0, 0}, {2, 0}};
2554
2555     armnn::INetworkPtr network = armnn::INetwork::Create();
2556     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2557     armnn::IConnectableLayer* const spaceToBatchNdLayer = network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2558     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2559
2560     inputLayer->GetOutputSlot(0).Connect(spaceToBatchNdLayer->GetInputSlot(0));
2561     spaceToBatchNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2562
2563     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2564     spaceToBatchNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2565
2566     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2567     BOOST_CHECK(deserializedNetwork);
2568
2569     SpaceToBatchNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2570     deserializedNetwork->Accept(verifier);
2571 }
2572
2573 BOOST_AUTO_TEST_CASE(SerializeSpaceToDepth)
2574 {
2575     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToDepth)
2576
2577     const std::string layerName("spaceToDepth");
2578
2579     const armnn::TensorInfo inputInfo ({ 1, 16, 8,  3 }, armnn::DataType::Float32);
2580     const armnn::TensorInfo outputInfo({ 1,  8, 4, 12 }, armnn::DataType::Float32);
2581
2582     armnn::SpaceToDepthDescriptor desc;
2583     desc.m_BlockSize  = 2;
2584     desc.m_DataLayout = armnn::DataLayout::NHWC;
2585
2586     armnn::INetworkPtr network = armnn::INetwork::Create();
2587     armnn::IConnectableLayer* const inputLayer        = network->AddInputLayer(0);
2588     armnn::IConnectableLayer* const spaceToDepthLayer = network->AddSpaceToDepthLayer(desc, layerName.c_str());
2589     armnn::IConnectableLayer* const outputLayer       = network->AddOutputLayer(0);
2590
2591     inputLayer->GetOutputSlot(0).Connect(spaceToDepthLayer->GetInputSlot(0));
2592     spaceToDepthLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2593
2594     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2595     spaceToDepthLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2596
2597     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2598     BOOST_CHECK(deserializedNetwork);
2599
2600     SpaceToDepthLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2601     deserializedNetwork->Accept(verifier);
2602 }
2603
2604 BOOST_AUTO_TEST_CASE(SerializeSplitter)
2605 {
2606     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Splitter)
2607
2608     const unsigned int numViews = 3;
2609     const unsigned int numDimensions = 4;
2610     const unsigned int inputShape[] = {1, 18, 4, 4};
2611     const unsigned int outputShape[] = {1, 6, 4, 4};
2612
2613     // This is modelled on how the caffe parser sets up a splitter layer to partition an input along dimension one.
2614     unsigned int splitterDimSizes[4] = {static_cast<unsigned int>(inputShape[0]),
2615                                         static_cast<unsigned int>(inputShape[1]),
2616                                         static_cast<unsigned int>(inputShape[2]),
2617                                         static_cast<unsigned int>(inputShape[3])};
2618     splitterDimSizes[1] /= numViews;
2619     armnn::ViewsDescriptor desc(numViews, numDimensions);
2620
2621     for (unsigned int g = 0; g < numViews; ++g)
2622     {
2623         desc.SetViewOriginCoord(g, 1, splitterDimSizes[1] * g);
2624
2625         for (unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
2626         {
2627             desc.SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
2628         }
2629     }
2630
2631     const std::string layerName("splitter");
2632     const armnn::TensorInfo inputInfo(numDimensions, inputShape, armnn::DataType::Float32);
2633     const armnn::TensorInfo outputInfo(numDimensions, outputShape, armnn::DataType::Float32);
2634
2635     armnn::INetworkPtr network = armnn::INetwork::Create();
2636     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2637     armnn::IConnectableLayer* const splitterLayer = network->AddSplitterLayer(desc, layerName.c_str());
2638     armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2639     armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2640     armnn::IConnectableLayer* const outputLayer2 = network->AddOutputLayer(2);
2641
2642     inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
2643     splitterLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2644     splitterLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2645     splitterLayer->GetOutputSlot(2).Connect(outputLayer2->GetInputSlot(0));
2646
2647     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2648     splitterLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2649     splitterLayer->GetOutputSlot(1).SetTensorInfo(outputInfo);
2650     splitterLayer->GetOutputSlot(2).SetTensorInfo(outputInfo);
2651
2652     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2653     BOOST_CHECK(deserializedNetwork);
2654
2655     SplitterLayerVerifier verifier(layerName, {inputInfo}, {outputInfo, outputInfo, outputInfo}, desc);
2656     deserializedNetwork->Accept(verifier);
2657 }
2658
2659 BOOST_AUTO_TEST_CASE(SerializeStack)
2660 {
2661     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Stack)
2662
2663     const std::string layerName("stack");
2664
2665     armnn::TensorInfo inputTensorInfo ({4, 3, 5}, armnn::DataType::Float32);
2666     armnn::TensorInfo outputTensorInfo({4, 3, 2, 5}, armnn::DataType::Float32);
2667
2668     armnn::StackDescriptor descriptor(2, 2, {4, 3, 5});
2669
2670     armnn::INetworkPtr network = armnn::INetwork::Create();
2671     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
2672     armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
2673     armnn::IConnectableLayer* const stackLayer = network->AddStackLayer(descriptor, layerName.c_str());
2674     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2675
2676     inputLayer1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
2677     inputLayer2->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
2678     stackLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2679
2680     inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2681     inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2682     stackLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2683
2684     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2685     BOOST_CHECK(deserializedNetwork);
2686
2687     StackLayerVerifier verifier(layerName, {inputTensorInfo, inputTensorInfo}, {outputTensorInfo}, descriptor);
2688     deserializedNetwork->Accept(verifier);
2689 }
2690
2691 BOOST_AUTO_TEST_CASE(SerializeStandIn)
2692 {
2693     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StandIn)
2694
2695     const std::string layerName("standIn");
2696
2697     armnn::TensorInfo tensorInfo({ 1u }, armnn::DataType::Float32);
2698     armnn::StandInDescriptor descriptor(2u, 2u);
2699
2700     armnn::INetworkPtr network = armnn::INetwork::Create();
2701     armnn::IConnectableLayer* const inputLayer0  = network->AddInputLayer(0);
2702     armnn::IConnectableLayer* const inputLayer1  = network->AddInputLayer(1);
2703     armnn::IConnectableLayer* const standInLayer = network->AddStandInLayer(descriptor, layerName.c_str());
2704     armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2705     armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2706
2707     inputLayer0->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(0));
2708     inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2709
2710     inputLayer1->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(1));
2711     inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2712
2713     standInLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2714     standInLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2715
2716     standInLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2717     standInLayer->GetOutputSlot(1).SetTensorInfo(tensorInfo);
2718
2719     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2720     BOOST_CHECK(deserializedNetwork);
2721
2722     StandInLayerVerifier verifier(layerName, { tensorInfo, tensorInfo }, { tensorInfo, tensorInfo }, descriptor);
2723     deserializedNetwork->Accept(verifier);
2724 }
2725
2726 BOOST_AUTO_TEST_CASE(SerializeStridedSlice)
2727 {
2728     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StridedSlice)
2729
2730     const std::string layerName("stridedSlice");
2731     const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2732     const armnn::TensorInfo outputInfo = armnn::TensorInfo({3, 1}, armnn::DataType::Float32);
2733
2734     armnn::StridedSliceDescriptor desc({0, 0, 1, 0}, {1, 1, 1, 1}, {1, 1, 1, 1});
2735     desc.m_EndMask = (1 << 4) - 1;
2736     desc.m_ShrinkAxisMask = (1 << 1) | (1 << 2);
2737     desc.m_DataLayout = armnn::DataLayout::NCHW;
2738
2739     armnn::INetworkPtr network = armnn::INetwork::Create();
2740     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2741     armnn::IConnectableLayer* const stridedSliceLayer = network->AddStridedSliceLayer(desc, layerName.c_str());
2742     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2743
2744     inputLayer->GetOutputSlot(0).Connect(stridedSliceLayer->GetInputSlot(0));
2745     stridedSliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2746
2747     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2748     stridedSliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2749
2750     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2751     BOOST_CHECK(deserializedNetwork);
2752
2753     StridedSliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2754     deserializedNetwork->Accept(verifier);
2755 }
2756
2757 BOOST_AUTO_TEST_CASE(SerializeSubtraction)
2758 {
2759     DECLARE_LAYER_VERIFIER_CLASS(Subtraction)
2760
2761     const std::string layerName("subtraction");
2762     const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2763
2764     armnn::INetworkPtr network = armnn::INetwork::Create();
2765     armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2766     armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2767     armnn::IConnectableLayer* const subtractionLayer = network->AddSubtractionLayer(layerName.c_str());
2768     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2769
2770     inputLayer0->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(0));
2771     inputLayer1->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(1));
2772     subtractionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2773
2774     inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2775     inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2776     subtractionLayer->GetOutputSlot(0).SetTensorInfo(info);
2777
2778     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2779     BOOST_CHECK(deserializedNetwork);
2780
2781     SubtractionLayerVerifier verifier(layerName, {info, info}, {info});
2782     deserializedNetwork->Accept(verifier);
2783 }
2784
2785 BOOST_AUTO_TEST_CASE(SerializeSwitch)
2786 {
2787     class SwitchLayerVerifier : public LayerVerifierBase
2788     {
2789     public:
2790         SwitchLayerVerifier(const std::string& layerName,
2791                             const std::vector<armnn::TensorInfo>& inputInfos,
2792                             const std::vector<armnn::TensorInfo>& outputInfos)
2793             : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2794
2795         void VisitSwitchLayer(const armnn::IConnectableLayer* layer, const char* name) override
2796         {
2797             VerifyNameAndConnections(layer, name);
2798         }
2799
2800         void VisitConstantLayer(const armnn::IConnectableLayer*,
2801                                 const armnn::ConstTensor&,
2802                                 const char*) override {}
2803     };
2804
2805     const std::string layerName("switch");
2806     const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2807
2808     std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2809     armnn::ConstTensor constTensor(info, constantData);
2810
2811     armnn::INetworkPtr network = armnn::INetwork::Create();
2812     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2813     armnn::IConnectableLayer* const constantLayer = network->AddConstantLayer(constTensor, "constant");
2814     armnn::IConnectableLayer* const switchLayer = network->AddSwitchLayer(layerName.c_str());
2815     armnn::IConnectableLayer* const trueOutputLayer = network->AddOutputLayer(0);
2816     armnn::IConnectableLayer* const falseOutputLayer = network->AddOutputLayer(1);
2817
2818     inputLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(0));
2819     constantLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(1));
2820     switchLayer->GetOutputSlot(0).Connect(trueOutputLayer->GetInputSlot(0));
2821     switchLayer->GetOutputSlot(1).Connect(falseOutputLayer->GetInputSlot(0));
2822
2823     inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2824     constantLayer->GetOutputSlot(0).SetTensorInfo(info);
2825     switchLayer->GetOutputSlot(0).SetTensorInfo(info);
2826     switchLayer->GetOutputSlot(1).SetTensorInfo(info);
2827
2828     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2829     BOOST_CHECK(deserializedNetwork);
2830
2831     SwitchLayerVerifier verifier(layerName, {info, info}, {info, info});
2832     deserializedNetwork->Accept(verifier);
2833 }
2834
2835 BOOST_AUTO_TEST_CASE(SerializeTranspose)
2836 {
2837     DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Transpose)
2838
2839     const std::string layerName("transpose");
2840     const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2841     const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2842
2843     armnn::TransposeDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2844
2845     armnn::INetworkPtr network = armnn::INetwork::Create();
2846     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2847     armnn::IConnectableLayer* const transposeLayer = network->AddTransposeLayer(descriptor, layerName.c_str());
2848     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2849
2850     inputLayer->GetOutputSlot(0).Connect(transposeLayer->GetInputSlot(0));
2851     transposeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2852
2853     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2854     transposeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2855
2856     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2857     BOOST_CHECK(deserializedNetwork);
2858
2859     TransposeLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2860     deserializedNetwork->Accept(verifier);
2861 }
2862
2863 BOOST_AUTO_TEST_CASE(SerializeTransposeConvolution2d)
2864 {
2865     using Descriptor = armnn::TransposeConvolution2dDescriptor;
2866     class TransposeConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
2867     {
2868     public:
2869         TransposeConvolution2dLayerVerifier(const std::string& layerName,
2870                                             const std::vector<armnn::TensorInfo>& inputInfos,
2871                                             const std::vector<armnn::TensorInfo>& outputInfos,
2872                                             const Descriptor& descriptor,
2873                                             const armnn::ConstTensor& weights,
2874                                             const armnn::Optional<armnn::ConstTensor>& biases)
2875             : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
2876             , m_Weights(weights)
2877             , m_Biases(biases)
2878         {}
2879
2880         void VisitTransposeConvolution2dLayer(const armnn::IConnectableLayer* layer,
2881                                               const Descriptor& descriptor,
2882                                               const armnn::ConstTensor& weights,
2883                                               const armnn::Optional<armnn::ConstTensor>& biases,
2884                                               const char* name) override
2885         {
2886             VerifyNameAndConnections(layer, name);
2887             VerifyDescriptor(descriptor);
2888
2889             // check weights
2890             CompareConstTensor(weights, m_Weights);
2891
2892             // check biases
2893             BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
2894             BOOST_CHECK(biases.has_value() == m_Biases.has_value());
2895
2896             if (biases.has_value() && m_Biases.has_value())
2897             {
2898                 CompareConstTensor(biases.value(), m_Biases.value());
2899             }
2900         }
2901
2902     private:
2903         armnn::ConstTensor                      m_Weights;
2904         armnn::Optional<armnn::ConstTensor>     m_Biases;
2905     };
2906
2907     const std::string layerName("transposeConvolution2d");
2908     const armnn::TensorInfo inputInfo ({ 1, 7, 7, 1 }, armnn::DataType::Float32);
2909     const armnn::TensorInfo outputInfo({ 1, 9, 9, 1 }, armnn::DataType::Float32);
2910
2911     const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
2912     const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
2913
2914     std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
2915     armnn::ConstTensor weights(weightsInfo, weightsData);
2916
2917     std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
2918     armnn::ConstTensor biases(biasesInfo, biasesData);
2919
2920     armnn::TransposeConvolution2dDescriptor descriptor;
2921     descriptor.m_PadLeft     = 1;
2922     descriptor.m_PadRight    = 1;
2923     descriptor.m_PadTop      = 1;
2924     descriptor.m_PadBottom   = 1;
2925     descriptor.m_StrideX     = 1;
2926     descriptor.m_StrideY     = 1;
2927     descriptor.m_BiasEnabled = true;
2928     descriptor.m_DataLayout  = armnn::DataLayout::NHWC;
2929
2930     armnn::INetworkPtr network = armnn::INetwork::Create();
2931     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
2932     armnn::IConnectableLayer* const convLayer   =
2933             network->AddTransposeConvolution2dLayer(descriptor,
2934                                                     weights,
2935                                                     armnn::Optional<armnn::ConstTensor>(biases),
2936                                                     layerName.c_str());
2937     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2938
2939     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
2940     convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2941
2942     inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2943     convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2944
2945     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2946     BOOST_CHECK(deserializedNetwork);
2947
2948     TransposeConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
2949     deserializedNetwork->Accept(verifier);
2950 }
2951
2952 BOOST_AUTO_TEST_CASE(SerializeDeserializeNonLinearNetwork)
2953 {
2954     class ConstantLayerVerifier : public LayerVerifierBase
2955     {
2956     public:
2957         ConstantLayerVerifier(const std::string& layerName,
2958                               const std::vector<armnn::TensorInfo>& inputInfos,
2959                               const std::vector<armnn::TensorInfo>& outputInfos,
2960                               const armnn::ConstTensor& layerInput)
2961             : LayerVerifierBase(layerName, inputInfos, outputInfos)
2962             , m_LayerInput(layerInput) {}
2963
2964         void VisitConstantLayer(const armnn::IConnectableLayer* layer,
2965                                 const armnn::ConstTensor& input,
2966                                 const char* name) override
2967         {
2968             VerifyNameAndConnections(layer, name);
2969             CompareConstTensor(input, m_LayerInput);
2970         }
2971
2972         void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
2973
2974     private:
2975         armnn::ConstTensor m_LayerInput;
2976     };
2977
2978     const std::string layerName("constant");
2979     const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
2980
2981     std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2982     armnn::ConstTensor constTensor(info, constantData);
2983
2984     armnn::INetworkPtr network(armnn::INetwork::Create());
2985     armnn::IConnectableLayer* input = network->AddInputLayer(0);
2986     armnn::IConnectableLayer* add = network->AddAdditionLayer();
2987     armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
2988     armnn::IConnectableLayer* output = network->AddOutputLayer(0);
2989
2990     input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
2991     constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
2992     add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2993
2994     input->GetOutputSlot(0).SetTensorInfo(info);
2995     constant->GetOutputSlot(0).SetTensorInfo(info);
2996     add->GetOutputSlot(0).SetTensorInfo(info);
2997
2998     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2999     BOOST_CHECK(deserializedNetwork);
3000
3001     ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
3002     deserializedNetwork->Accept(verifier);
3003 }
3004
3005 class VerifyLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>
3006 {
3007 public:
3008     VerifyLstmLayer(const std::string& layerName,
3009                     const std::vector<armnn::TensorInfo>& inputInfos,
3010                     const std::vector<armnn::TensorInfo>& outputInfos,
3011                     const armnn::LstmDescriptor& descriptor,
3012                     const armnn::LstmInputParams& inputParams)
3013         : LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
3014         , m_InputParams(inputParams) {}
3015
3016     void VisitLstmLayer(const armnn::IConnectableLayer* layer,
3017                         const armnn::LstmDescriptor& descriptor,
3018                         const armnn::LstmInputParams& params,
3019                         const char* name)
3020     {
3021         VerifyNameAndConnections(layer, name);
3022         VerifyDescriptor(descriptor);
3023         VerifyInputParameters(params);
3024     }
3025
3026 protected:
3027     void VerifyInputParameters(const armnn::LstmInputParams& params)
3028     {
3029         VerifyConstTensors(
3030             "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
3031         VerifyConstTensors(
3032             "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
3033         VerifyConstTensors(
3034             "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
3035         VerifyConstTensors(
3036             "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
3037         VerifyConstTensors(
3038             "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
3039         VerifyConstTensors(
3040             "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
3041         VerifyConstTensors(
3042             "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
3043         VerifyConstTensors(
3044             "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
3045         VerifyConstTensors(
3046             "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
3047         VerifyConstTensors(
3048             "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
3049         VerifyConstTensors(
3050             "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
3051         VerifyConstTensors(
3052             "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
3053         VerifyConstTensors(
3054             "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
3055         VerifyConstTensors(
3056             "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
3057         VerifyConstTensors(
3058             "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
3059         VerifyConstTensors(
3060             "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
3061         VerifyConstTensors(
3062             "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
3063         VerifyConstTensors(
3064             "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
3065         VerifyConstTensors(
3066             "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
3067         VerifyConstTensors(
3068             "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
3069         VerifyConstTensors(
3070             "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
3071     }
3072
3073 private:
3074     armnn::LstmInputParams m_InputParams;
3075 };
3076
3077 BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmCifgPeepholeNoProjection)
3078 {
3079     armnn::LstmDescriptor descriptor;
3080     descriptor.m_ActivationFunc = 4;
3081     descriptor.m_ClippingThresProj = 0.0f;
3082     descriptor.m_ClippingThresCell = 0.0f;
3083     descriptor.m_CifgEnabled = true; // if this is true then we DON'T need to set the OptCifgParams
3084     descriptor.m_ProjectionEnabled = false;
3085     descriptor.m_PeepholeEnabled = true;
3086
3087     const uint32_t batchSize = 1;
3088     const uint32_t inputSize = 2;
3089     const uint32_t numUnits = 4;
3090     const uint32_t outputSize = numUnits;
3091
3092     armnn::TensorInfo inputWeightsInfo1({numUnits, inputSize}, armnn::DataType::Float32);
3093     std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3094     armnn::ConstTensor inputToForgetWeights(inputWeightsInfo1, inputToForgetWeightsData);
3095
3096     std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3097     armnn::ConstTensor inputToCellWeights(inputWeightsInfo1, inputToCellWeightsData);
3098
3099     std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3100     armnn::ConstTensor inputToOutputWeights(inputWeightsInfo1, inputToOutputWeightsData);
3101
3102     armnn::TensorInfo inputWeightsInfo2({numUnits, outputSize}, armnn::DataType::Float32);
3103     std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3104     armnn::ConstTensor recurrentToForgetWeights(inputWeightsInfo2, recurrentToForgetWeightsData);
3105
3106     std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3107     armnn::ConstTensor recurrentToCellWeights(inputWeightsInfo2, recurrentToCellWeightsData);
3108
3109     std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3110     armnn::ConstTensor recurrentToOutputWeights(inputWeightsInfo2, recurrentToOutputWeightsData);
3111
3112     armnn::TensorInfo inputWeightsInfo3({numUnits}, armnn::DataType::Float32);
3113     std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3114     armnn::ConstTensor cellToForgetWeights(inputWeightsInfo3, cellToForgetWeightsData);
3115
3116     std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3117     armnn::ConstTensor cellToOutputWeights(inputWeightsInfo3, cellToOutputWeightsData);
3118
3119     std::vector<float> forgetGateBiasData(numUnits, 1.0f);
3120     armnn::ConstTensor forgetGateBias(inputWeightsInfo3, forgetGateBiasData);
3121
3122     std::vector<float> cellBiasData(numUnits, 0.0f);
3123     armnn::ConstTensor cellBias(inputWeightsInfo3, cellBiasData);
3124
3125     std::vector<float> outputGateBiasData(numUnits, 0.0f);
3126     armnn::ConstTensor outputGateBias(inputWeightsInfo3, outputGateBiasData);
3127
3128     armnn::LstmInputParams params;
3129     params.m_InputToForgetWeights = &inputToForgetWeights;
3130     params.m_InputToCellWeights = &inputToCellWeights;
3131     params.m_InputToOutputWeights = &inputToOutputWeights;
3132     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3133     params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3134     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3135     params.m_ForgetGateBias = &forgetGateBias;
3136     params.m_CellBias = &cellBias;
3137     params.m_OutputGateBias = &outputGateBias;
3138     params.m_CellToForgetWeights = &cellToForgetWeights;
3139     params.m_CellToOutputWeights = &cellToOutputWeights;
3140
3141     armnn::INetworkPtr network = armnn::INetwork::Create();
3142     armnn::IConnectableLayer* const inputLayer   = network->AddInputLayer(0);
3143     armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3144     armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3145     const std::string layerName("lstm");
3146     armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3147     armnn::IConnectableLayer* const scratchBuffer  = network->AddOutputLayer(0);
3148     armnn::IConnectableLayer* const outputStateOut  = network->AddOutputLayer(1);
3149     armnn::IConnectableLayer* const cellStateOut  = network->AddOutputLayer(2);
3150     armnn::IConnectableLayer* const outputLayer  = network->AddOutputLayer(3);
3151
3152     // connect up
3153     armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3154     armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3155     armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3156     armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 3 }, armnn::DataType::Float32);
3157
3158     inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3159     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3160
3161     outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3162     outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3163
3164     cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3165     cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3166
3167     lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3168     lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3169
3170     lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3171     lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3172
3173     lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3174     lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3175
3176     lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3177     lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3178
3179     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3180     BOOST_CHECK(deserializedNetwork);
3181
3182     VerifyLstmLayer checker(
3183         layerName,
3184         {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3185         {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3186         descriptor,
3187         params);
3188     deserializedNetwork->Accept(checker);
3189 }
3190
3191 BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeAndProjection)
3192 {
3193     armnn::LstmDescriptor descriptor;
3194     descriptor.m_ActivationFunc = 4;
3195     descriptor.m_ClippingThresProj = 0.0f;
3196     descriptor.m_ClippingThresCell = 0.0f;
3197     descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3198     descriptor.m_ProjectionEnabled = true;
3199     descriptor.m_PeepholeEnabled = true;
3200
3201     const uint32_t batchSize = 2;
3202     const uint32_t inputSize = 5;
3203     const uint32_t numUnits = 20;
3204     const uint32_t outputSize = 16;
3205
3206     armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3207     std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3208     armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3209
3210     std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3211     armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3212
3213     std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3214     armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3215
3216     std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3217     armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3218
3219     armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3220     std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3221     armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3222
3223     std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3224     armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3225
3226     std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3227     armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3228
3229     std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3230     armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3231
3232     armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3233     std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3234     armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3235
3236     std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3237     armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3238
3239     std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3240     armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3241
3242     std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3243     armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3244
3245     std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3246     armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3247
3248     std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3249     armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3250
3251     std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3252     armnn::ConstTensor cellToOutputWeights(tensorInfo20,  cellToOutputWeightsData);
3253
3254     armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3255     std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3256     armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3257
3258     armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3259     std::vector<float> projectionBiasData(outputSize, 0.f);
3260     armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3261
3262     armnn::LstmInputParams params;
3263     params.m_InputToForgetWeights = &inputToForgetWeights;
3264     params.m_InputToCellWeights = &inputToCellWeights;
3265     params.m_InputToOutputWeights = &inputToOutputWeights;
3266     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3267     params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3268     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3269     params.m_ForgetGateBias = &forgetGateBias;
3270     params.m_CellBias = &cellBias;
3271     params.m_OutputGateBias = &outputGateBias;
3272
3273     // additional params because: descriptor.m_CifgEnabled = false
3274     params.m_InputToInputWeights = &inputToInputWeights;
3275     params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3276     params.m_CellToInputWeights = &cellToInputWeights;
3277     params.m_InputGateBias = &inputGateBias;
3278
3279     // additional params because: descriptor.m_ProjectionEnabled = true
3280     params.m_ProjectionWeights = &projectionWeights;
3281     params.m_ProjectionBias = &projectionBias;
3282
3283     // additional params because: descriptor.m_PeepholeEnabled = true
3284     params.m_CellToForgetWeights = &cellToForgetWeights;
3285     params.m_CellToOutputWeights = &cellToOutputWeights;
3286
3287     armnn::INetworkPtr network = armnn::INetwork::Create();
3288     armnn::IConnectableLayer* const inputLayer   = network->AddInputLayer(0);
3289     armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3290     armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3291     const std::string layerName("lstm");
3292     armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3293     armnn::IConnectableLayer* const scratchBuffer  = network->AddOutputLayer(0);
3294     armnn::IConnectableLayer* const outputStateOut  = network->AddOutputLayer(1);
3295     armnn::IConnectableLayer* const cellStateOut  = network->AddOutputLayer(2);
3296     armnn::IConnectableLayer* const outputLayer  = network->AddOutputLayer(3);
3297
3298     // connect up
3299     armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3300     armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3301     armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3302     armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3303
3304     inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3305     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3306
3307     outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3308     outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3309
3310     cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3311     cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3312
3313     lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3314     lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3315
3316     lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3317     lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3318
3319     lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3320     lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3321
3322     lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3323     lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3324
3325     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3326     BOOST_CHECK(deserializedNetwork);
3327
3328     VerifyLstmLayer checker(
3329         layerName,
3330         {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3331         {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3332         descriptor,
3333         params);
3334     deserializedNetwork->Accept(checker);
3335 }
3336
3337 BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeWithProjectionWithLayerNorm)
3338 {
3339     armnn::LstmDescriptor descriptor;
3340     descriptor.m_ActivationFunc = 4;
3341     descriptor.m_ClippingThresProj = 0.0f;
3342     descriptor.m_ClippingThresCell = 0.0f;
3343     descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3344     descriptor.m_ProjectionEnabled = true;
3345     descriptor.m_PeepholeEnabled = true;
3346     descriptor.m_LayerNormEnabled = true;
3347
3348     const uint32_t batchSize = 2;
3349     const uint32_t inputSize = 5;
3350     const uint32_t numUnits = 20;
3351     const uint32_t outputSize = 16;
3352
3353     armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3354     std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3355     armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3356
3357     std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3358     armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3359
3360     std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3361     armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3362
3363     std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3364     armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3365
3366     armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3367     std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3368     armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3369
3370     std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3371     armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3372
3373     std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3374     armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3375
3376     std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3377     armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3378
3379     armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3380     std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3381     armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3382
3383     std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3384     armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3385
3386     std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3387     armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3388
3389     std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3390     armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3391
3392     std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3393     armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3394
3395     std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3396     armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3397
3398     std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3399     armnn::ConstTensor cellToOutputWeights(tensorInfo20,  cellToOutputWeightsData);
3400
3401     armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3402     std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3403     armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3404
3405     armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3406     std::vector<float> projectionBiasData(outputSize, 0.f);
3407     armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3408
3409     std::vector<float> inputLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3410     armnn::ConstTensor inputLayerNormWeights(tensorInfo20, forgetGateBiasData);
3411
3412     std::vector<float> forgetLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3413     armnn::ConstTensor forgetLayerNormWeights(tensorInfo20, forgetGateBiasData);
3414
3415     std::vector<float> cellLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3416     armnn::ConstTensor cellLayerNormWeights(tensorInfo20, forgetGateBiasData);
3417
3418     std::vector<float> outLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3419     armnn::ConstTensor outLayerNormWeights(tensorInfo20, forgetGateBiasData);
3420
3421     armnn::LstmInputParams params;
3422     params.m_InputToForgetWeights = &inputToForgetWeights;
3423     params.m_InputToCellWeights = &inputToCellWeights;
3424     params.m_InputToOutputWeights = &inputToOutputWeights;
3425     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3426     params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3427     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3428     params.m_ForgetGateBias = &forgetGateBias;
3429     params.m_CellBias = &cellBias;
3430     params.m_OutputGateBias = &outputGateBias;
3431
3432     // additional params because: descriptor.m_CifgEnabled = false
3433     params.m_InputToInputWeights = &inputToInputWeights;
3434     params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3435     params.m_CellToInputWeights = &cellToInputWeights;
3436     params.m_InputGateBias = &inputGateBias;
3437
3438     // additional params because: descriptor.m_ProjectionEnabled = true
3439     params.m_ProjectionWeights = &projectionWeights;
3440     params.m_ProjectionBias = &projectionBias;
3441
3442     // additional params because: descriptor.m_PeepholeEnabled = true
3443     params.m_CellToForgetWeights = &cellToForgetWeights;
3444     params.m_CellToOutputWeights = &cellToOutputWeights;
3445
3446     // additional params because: despriptor.m_LayerNormEnabled = true
3447     params.m_InputLayerNormWeights = &inputLayerNormWeights;
3448     params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3449     params.m_CellLayerNormWeights = &cellLayerNormWeights;
3450     params.m_OutputLayerNormWeights = &outLayerNormWeights;
3451
3452     armnn::INetworkPtr network = armnn::INetwork::Create();
3453     armnn::IConnectableLayer* const inputLayer   = network->AddInputLayer(0);
3454     armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3455     armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3456     const std::string layerName("lstm");
3457     armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3458     armnn::IConnectableLayer* const scratchBuffer  = network->AddOutputLayer(0);
3459     armnn::IConnectableLayer* const outputStateOut  = network->AddOutputLayer(1);
3460     armnn::IConnectableLayer* const cellStateOut  = network->AddOutputLayer(2);
3461     armnn::IConnectableLayer* const outputLayer  = network->AddOutputLayer(3);
3462
3463     // connect up
3464     armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3465     armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3466     armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3467     armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3468
3469     inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3470     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3471
3472     outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3473     outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3474
3475     cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3476     cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3477
3478     lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3479     lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3480
3481     lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3482     lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3483
3484     lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3485     lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3486
3487     lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3488     lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3489
3490     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3491     BOOST_CHECK(deserializedNetwork);
3492
3493     VerifyLstmLayer checker(
3494             layerName,
3495             {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3496             {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3497             descriptor,
3498             params);
3499     deserializedNetwork->Accept(checker);
3500 }
3501
3502 BOOST_AUTO_TEST_CASE(EnsureLstmLayersBackwardCompatibility)
3503 {
3504     // The hex data below is a flat buffer containing a lstm layer with no Cifg, with peephole and projection
3505     // enabled. That data was obtained before additional layer normalization parameters where added to the
3506     // lstm serializer. That way it can be tested if a lstm model with the old parameter configuration can
3507     // still be loaded
3508     const std::vector<uint8_t> lstmNoCifgWithPeepholeAndProjectionModel =
3509     {
3510         0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
3511         0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
3512         0xDC, 0x29, 0x00, 0x00, 0x38, 0x29, 0x00, 0x00, 0xB4, 0x28, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x3C, 0x01,
3513         0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
3514         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
3515         0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0xD6, 0xFF, 0xFF,
3516         0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x06, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x88, 0xD7,
3517         0xFF, 0xFF, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF6, 0xD6, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
3518         0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
3519         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3520         0xE8, 0xD7, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xFF, 0xFF, 0x00, 0x00,
3521         0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x5E, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xE0, 0xD7, 0xFF, 0xFF,
3522         0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4E, 0xD7, 0xFF, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00,
3523         0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3524         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD8,
3525         0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
3526         0x04, 0x00, 0x00, 0x00, 0xB6, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x38, 0xD8, 0xFF, 0xFF, 0x08, 0x00,
3527         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA6, 0xD7, 0xFF, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3528         0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3529         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xD8, 0xFF, 0xFF,
3530         0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00,
3531         0x00, 0x00, 0x0E, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x16, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3532         0xFA, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00,
3533         0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3534         0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
3535         0x00, 0x00, 0x6C, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
3536         0x12, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE0, 0x25, 0x00, 0x00, 0xD0, 0x25,
3537         0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x48, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00,
3538         0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2C, 0x00, 0x30, 0x00,
3539         0x34, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x40, 0x00, 0x44, 0x00, 0x26, 0x00, 0x00, 0x00, 0xC4, 0x23, 0x00, 0x00,
3540         0xF8, 0x21, 0x00, 0x00, 0x2C, 0x20, 0x00, 0x00, 0xF0, 0x1A, 0x00, 0x00, 0xB4, 0x15, 0x00, 0x00, 0x78, 0x10,
3541         0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x68, 0x0F, 0x00, 0x00, 0xE0, 0x0E, 0x00, 0x00, 0x14, 0x0D, 0x00, 0x00,
3542         0xD8, 0x07, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0xC8, 0x06, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x14, 0x01,
3543         0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3544         0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00,
3545         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3546         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3547         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3548         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3549         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3550         0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x72, 0xD8,
3551         0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0xD9, 0xFF, 0xFF,
3552         0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3553         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3554         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3555         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3556         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xD8,
3557         0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3558         0x14, 0x00, 0x00, 0x00, 0xF6, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x54, 0x00, 0x00, 0x00, 0x04, 0x00,
3559         0x00, 0x00, 0x06, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3560         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3561         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3562         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3563         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xD9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3564         0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6A, 0xD9, 0xFF, 0xFF, 0x00, 0x00,
3565         0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7A, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3566         0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3567         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3568         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3569         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3570         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3571         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3572         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3573         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3574         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3575         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3576         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3577         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3578         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3579         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3580         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3581         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3582         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3583         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3584         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3585         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3586         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3587         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3588         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3589         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3590         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3591         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3592         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3593         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3594         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3595         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3596         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3597         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3598         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3599         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3600         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3601         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3602         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3603         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3604         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3605         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3606         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3607         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3608         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3609         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3610         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3611         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3612         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3613         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3614         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3615         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3616         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3617         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3618         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3619         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3620         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3621         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3622         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3623         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3624         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3625         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3626         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3627         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3628         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3629         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3630         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3631         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3632         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3633         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3634         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3635         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3636         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3637         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xDE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3638         0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xA2, 0xDE,
3639         0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB2, 0xDF, 0xFF, 0xFF,
3640         0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3641         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3642         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3643         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3644         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xDF,
3645         0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3646         0x14, 0x00, 0x00, 0x00, 0x26, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00,
3647         0x00, 0x00, 0x36, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3648         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3649         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3650         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3651         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3652         0x00, 0x00, 0x00, 0x00, 0x92, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3653         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAA, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3654         0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xBA, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3655         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3656         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3657         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3658         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3659         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3660         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3661         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3662         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3663         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3664         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3665         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3666         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3667         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3668         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3669         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3670         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3671         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3672         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3673         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3674         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3675         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3676         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3677         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3678         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3679         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3680         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3681         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3682         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3683         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3684         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3685         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3686         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3687         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3688         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3689         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3690         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3691         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3692         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3693         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3694         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3695         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3696         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3697         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3698         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3699         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3700         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3701         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3702         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3703         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3704         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3705         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3706         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3707         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3708         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3709         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3710         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3711         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3712         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3713         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3714         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3715         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3716         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3717         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3718         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3719         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3720         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3721         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3722         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3723         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3724         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3725         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3726         0x00, 0x00, 0x00, 0x00, 0xC6, 0xE4, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3727         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xE2, 0xE4, 0xFF, 0xFF,
3728         0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xE5, 0xFF, 0xFF, 0x04, 0x00,
3729         0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3730         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3731         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3732         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3733         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3734         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3735         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3736         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3737         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3738         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3739         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3740         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3741         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3742         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3743         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3744         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3745         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3746         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3747         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3748         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3749         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3750         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3751         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3752         0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
3753         0x00, 0x00, 0xAA, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3754         0xBA, 0xE7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3755         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3756         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3757         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3758         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3759         0x00, 0x00, 0x16, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3760         0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2E, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00,
3761         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3E, 0xE8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
3762         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3763         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3764         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3765         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3766         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3767         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xB2, 0xE7, 0xFF, 0xFF,
3768         0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC2, 0xE8, 0xFF, 0xFF, 0x04, 0x00,
3769         0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3770         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3771         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3772         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3773         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE8, 0xFF, 0xFF,
3774         0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00,
3775         0x00, 0x00, 0x36, 0xE8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3776         0x46, 0xE9, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3777         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3778         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3779         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3780         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3781         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3782         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3783         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3784         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3785         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3786         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3787         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3788         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3789         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3790         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3791         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3792         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3793         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3794         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3795         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3796         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3797         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3798         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3799         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3800         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3801         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3802         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3803         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3804         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3805         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3806         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3807         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3808         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3809         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3810         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3811         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3812         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3813         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3814         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3815         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3816         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3817         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3818         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3819         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3820         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3821         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3822         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3823         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3824         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3825         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3826         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3827         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3828         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3829         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3830         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3831         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3832         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3833         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3834         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3835         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3836         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3837         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3838         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3839         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3840         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3841         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3842         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3843         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3844         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3845         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3846         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3847         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0xFF, 0xFF,
3848         0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00,
3849         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6E, 0xED, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00,
3850         0x04, 0x00, 0x00, 0x00, 0x7E, 0xEE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00,
3851         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3852         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3853         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3854         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3855         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3856         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3857         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3858         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3859         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3860         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3861         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3862         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3863         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3864         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3865         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3866         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3867         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3868         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3869         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3870         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3871         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3872         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3873         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3874         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3875         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3876         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3877         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3878         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3879         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3880         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3881         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3882         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3883         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3884         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3885         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3886         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3887         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3888         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3889         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3890         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3891         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3892         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3893         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3894         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3895         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3896         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3897         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3898         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3899         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3900         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3901         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3902         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3903         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3904         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3905         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3906         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3907         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3908         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3909         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3910         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3911         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3912         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3913         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3914         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3915         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3916         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3917         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3918         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3919         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3920         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3921         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3922         0x8A, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3923         0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xA6, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3924         0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB6, 0xF3, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3925         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3926         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3927         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3928         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3929         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3930         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3931         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3932         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3933         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3934         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3935         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3936         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3937         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3938         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3939         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3940         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3941         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3942         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3943         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3944         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3945         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3946         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3947         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3948         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3949         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3950         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3951         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3952         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3953         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3954         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3955         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3956         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3957         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3958         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3959         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3960         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3961         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3962         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3963         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3964         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3965         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3966         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3967         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3968         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3969         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3970         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3971         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3972         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3973         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3974         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3975         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3976         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3977         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3978         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3979         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3980         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3981         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3982         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3983         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3984         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3985         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3986         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3987         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3988         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3989         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3990         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3991         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3992         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3993         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3994         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3995         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3996         0x00, 0x00, 0x00, 0x00, 0xC2, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3997         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xDE, 0xF7, 0xFF, 0xFF,
3998         0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xF8, 0xFF, 0xFF, 0x04, 0x00,
3999         0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4000         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4001         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4002         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4003         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4004         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4005         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4006         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4007         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4008         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4009         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4010         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4011         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4012         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4013         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4014         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4015         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4016         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4017         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4018         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4019         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4020         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4021         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
4022         0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
4023         0x00, 0x00, 0xA6, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4024         0xB6, 0xFA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4025         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4026         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4027         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4028         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4029         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4030         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4031         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4032         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4033         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4034         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4035         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4036         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4037         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4038         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4039         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4040         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4041         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4042         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4043         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4044         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4045         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4046         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xFB,
4047         0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
4048         0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6E, 0xFB, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01,
4049         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFC, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
4050         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4051         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4052         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4053         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4054         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4055         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4056         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4057         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4058         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4059         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4060         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4061         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4062         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4063         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4064         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4065         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4066         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4067         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4068         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4069         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4070         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4071         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4072         0x00, 0x00, 0x00, 0x00, 0x1A, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4073         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x00,
4074         0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
4075         0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x2E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4076         0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6C, 0x73,
4077         0x74, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00,
4078         0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x30, 0x00,
4079         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4080         0xA6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
4081         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
4082         0x04, 0x00, 0x00, 0x00, 0xCE, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4083         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x64, 0xFF, 0xFF, 0xFF,
4084         0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4085         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4086         0xB4, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x1A, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4087         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
4088         0xF0, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
4089         0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
4090         0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4091         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
4092         0x7E, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00,
4093         0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x76, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
4094         0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
4095         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4096         0x68, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4097         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4098         0x08, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00,
4099         0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4100         0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00,
4101         0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00,
4102         0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
4103         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4104         0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4105         0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6E, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
4106         0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00,
4107         0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
4108         0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00,
4109         0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4110         0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
4111         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4112         0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4113         0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00,
4114         0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
4115         0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00
4116     };
4117
4118     armnn::INetworkPtr deserializedNetwork =
4119         DeserializeNetwork(std::string(lstmNoCifgWithPeepholeAndProjectionModel.begin(),
4120                                        lstmNoCifgWithPeepholeAndProjectionModel.end()));
4121
4122     BOOST_CHECK(deserializedNetwork);
4123
4124     // generating the same model parameters which where used to serialize the model (Layer norm is not specified)
4125     armnn::LstmDescriptor descriptor;
4126     descriptor.m_ActivationFunc    = 4;
4127     descriptor.m_ClippingThresProj = 0.0f;
4128     descriptor.m_ClippingThresCell = 0.0f;
4129     descriptor.m_CifgEnabled       = false;
4130     descriptor.m_ProjectionEnabled = true;
4131     descriptor.m_PeepholeEnabled   = true;
4132
4133     const uint32_t batchSize  = 2u;
4134     const uint32_t inputSize  = 5u;
4135     const uint32_t numUnits   = 20u;
4136     const uint32_t outputSize = 16u;
4137
4138     armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
4139     std::vector<float> inputToInputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4140     armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
4141
4142     std::vector<float> inputToForgetWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4143     armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
4144
4145     std::vector<float> inputToCellWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4146     armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
4147
4148     std::vector<float> inputToOutputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4149     armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
4150
4151     armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
4152     std::vector<float> inputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4153     armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
4154
4155     std::vector<float> forgetGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4156     armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
4157
4158     std::vector<float> cellBiasData(tensorInfo20.GetNumElements(), 0.0f);
4159     armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
4160
4161     std::vector<float> outputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4162     armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
4163
4164     armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
4165     std::vector<float> recurrentToInputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4166     armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
4167
4168     std::vector<float> recurrentToForgetWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4169     armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
4170
4171     std::vector<float> recurrentToCellWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4172     armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
4173
4174     std::vector<float> recurrentToOutputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4175     armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
4176
4177     std::vector<float> cellToInputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4178     armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
4179
4180     std::vector<float> cellToForgetWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4181     armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
4182
4183     std::vector<float> cellToOutputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4184     armnn::ConstTensor cellToOutputWeights(tensorInfo20,  cellToOutputWeightsData);
4185
4186     armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
4187     std::vector<float> projectionWeightsData(tensorInfo16x20.GetNumElements(), 0.0f);
4188     armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
4189
4190     armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
4191     std::vector<float> projectionBiasData(outputSize, 0.0f);
4192     armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
4193
4194     armnn::LstmInputParams params;
4195     params.m_InputToForgetWeights     = &inputToForgetWeights;
4196     params.m_InputToCellWeights       = &inputToCellWeights;
4197     params.m_InputToOutputWeights     = &inputToOutputWeights;
4198     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4199     params.m_RecurrentToCellWeights   = &recurrentToCellWeights;
4200     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4201     params.m_ForgetGateBias           = &forgetGateBias;
4202     params.m_CellBias                 = &cellBias;
4203     params.m_OutputGateBias           = &outputGateBias;
4204
4205     // additional params because: descriptor.m_CifgEnabled = false
4206     params.m_InputToInputWeights      = &inputToInputWeights;
4207     params.m_RecurrentToInputWeights  = &recurrentToInputWeights;
4208     params.m_CellToInputWeights       = &cellToInputWeights;
4209     params.m_InputGateBias            = &inputGateBias;
4210
4211     // additional params because: descriptor.m_ProjectionEnabled = true
4212     params.m_ProjectionWeights        = &projectionWeights;
4213     params.m_ProjectionBias           = &projectionBias;
4214
4215     // additional params because: descriptor.m_PeepholeEnabled = true
4216     params.m_CellToForgetWeights      = &cellToForgetWeights;
4217     params.m_CellToOutputWeights      = &cellToOutputWeights;
4218
4219     const std::string layerName("lstm");
4220     armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
4221     armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
4222     armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
4223     armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
4224
4225     VerifyLstmLayer checker(
4226             layerName,
4227             {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
4228             {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4229             descriptor,
4230             params);
4231     deserializedNetwork->Accept(checker);
4232 }
4233 class VerifyQuantizedLstmLayer : public LayerVerifierBase
4234 {
4235
4236 public:
4237     VerifyQuantizedLstmLayer(const std::string& layerName,
4238                              const std::vector<armnn::TensorInfo>& inputInfos,
4239                              const std::vector<armnn::TensorInfo>& outputInfos,
4240                              const armnn::QuantizedLstmInputParams& inputParams)
4241         : LayerVerifierBase(layerName, inputInfos, outputInfos), m_InputParams(inputParams) {}
4242
4243     void VisitQuantizedLstmLayer(const armnn::IConnectableLayer* layer,
4244                                  const armnn::QuantizedLstmInputParams& params,
4245                                  const char* name)
4246     {
4247         VerifyNameAndConnections(layer, name);
4248         VerifyInputParameters(params);
4249     }
4250
4251 protected:
4252     void VerifyInputParameters(const armnn::QuantizedLstmInputParams& params)
4253     {
4254         VerifyConstTensors("m_InputToInputWeights",
4255                            m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4256         VerifyConstTensors("m_InputToForgetWeights",
4257                            m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4258         VerifyConstTensors("m_InputToCellWeights",
4259                            m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4260         VerifyConstTensors("m_InputToOutputWeights",
4261                            m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4262         VerifyConstTensors("m_RecurrentToInputWeights",
4263                            m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4264         VerifyConstTensors("m_RecurrentToForgetWeights",
4265                            m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4266         VerifyConstTensors("m_RecurrentToCellWeights",
4267                            m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4268         VerifyConstTensors("m_RecurrentToOutputWeights",
4269                            m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4270         VerifyConstTensors("m_InputGateBias",
4271                            m_InputParams.m_InputGateBias, params.m_InputGateBias);
4272         VerifyConstTensors("m_ForgetGateBias",
4273                            m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4274         VerifyConstTensors("m_CellBias",
4275                            m_InputParams.m_CellBias, params.m_CellBias);
4276         VerifyConstTensors("m_OutputGateBias",
4277                            m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4278     }
4279
4280 private:
4281     armnn::QuantizedLstmInputParams m_InputParams;
4282 };
4283
4284 BOOST_AUTO_TEST_CASE(SerializeDeserializeQuantizedLstm)
4285 {
4286     const uint32_t batchSize = 1;
4287     const uint32_t inputSize = 2;
4288     const uint32_t numUnits = 4;
4289     const uint32_t outputSize = numUnits;
4290
4291     // Scale/Offset for input/output, cellState In/Out, weights, bias
4292     float inputOutputScale = 0.0078125f;
4293     int32_t inputOutputOffset = 128;
4294
4295     float cellStateScale = 0.00048828125f;
4296     int32_t cellStateOffset = 0;
4297
4298     float weightsScale = 0.00408021f;
4299     int32_t weightsOffset = 100;
4300
4301     float biasScale = 3.1876640625e-05f;
4302     int32_t biasOffset = 0;
4303
4304     // The shape of weight data is {outputSize, inputSize} = {4, 2}
4305     armnn::TensorShape inputToInputWeightsShape = {4, 2};
4306     std::vector<uint8_t> inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4307     armnn::TensorInfo inputToInputWeightsInfo(inputToInputWeightsShape,
4308                                               armnn::DataType::QAsymmU8,
4309                                               weightsScale,
4310                                               weightsOffset);
4311     armnn::ConstTensor inputToInputWeights(inputToInputWeightsInfo, inputToInputWeightsData);
4312
4313     armnn::TensorShape inputToForgetWeightsShape = {4, 2};
4314     std::vector<uint8_t> inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4315     armnn::TensorInfo inputToForgetWeightsInfo(inputToForgetWeightsShape,
4316                                                armnn::DataType::QAsymmU8,
4317                                                weightsScale,
4318                                                weightsOffset);
4319     armnn::ConstTensor inputToForgetWeights(inputToForgetWeightsInfo, inputToForgetWeightsData);
4320
4321     armnn::TensorShape inputToCellWeightsShape = {4, 2};
4322     std::vector<uint8_t> inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4323     armnn::TensorInfo inputToCellWeightsInfo(inputToCellWeightsShape,
4324                                              armnn::DataType::QAsymmU8,
4325                                              weightsScale,
4326                                              weightsOffset);
4327     armnn::ConstTensor inputToCellWeights(inputToCellWeightsInfo, inputToCellWeightsData);
4328
4329     armnn::TensorShape inputToOutputWeightsShape = {4, 2};
4330     std::vector<uint8_t> inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4331     armnn::TensorInfo inputToOutputWeightsInfo(inputToOutputWeightsShape,
4332                                                armnn::DataType::QAsymmU8,
4333                                                weightsScale,
4334                                                weightsOffset);
4335     armnn::ConstTensor inputToOutputWeights(inputToOutputWeightsInfo, inputToOutputWeightsData);
4336
4337     // The shape of recurrent weight data is {outputSize, outputSize} = {4, 4}
4338     armnn::TensorShape recurrentToInputWeightsShape = {4, 4};
4339     std::vector<uint8_t> recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4340     armnn::TensorInfo recurrentToInputWeightsInfo(recurrentToInputWeightsShape,
4341                                                   armnn::DataType::QAsymmU8,
4342                                                   weightsScale,
4343                                                   weightsOffset);
4344     armnn::ConstTensor recurrentToInputWeights(recurrentToInputWeightsInfo, recurrentToInputWeightsData);
4345
4346     armnn::TensorShape recurrentToForgetWeightsShape = {4, 4};
4347     std::vector<uint8_t> recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4348     armnn::TensorInfo recurrentToForgetWeightsInfo(recurrentToForgetWeightsShape,
4349                                                    armnn::DataType::QAsymmU8,
4350                                                    weightsScale,
4351                                                    weightsOffset);
4352     armnn::ConstTensor recurrentToForgetWeights(recurrentToForgetWeightsInfo, recurrentToForgetWeightsData);
4353
4354     armnn::TensorShape recurrentToCellWeightsShape = {4, 4};
4355     std::vector<uint8_t> recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4356     armnn::TensorInfo recurrentToCellWeightsInfo(recurrentToCellWeightsShape,
4357                                                  armnn::DataType::QAsymmU8,
4358                                                  weightsScale,
4359                                                  weightsOffset);
4360     armnn::ConstTensor recurrentToCellWeights(recurrentToCellWeightsInfo, recurrentToCellWeightsData);
4361
4362     armnn::TensorShape recurrentToOutputWeightsShape = {4, 4};
4363     std::vector<uint8_t> recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4364     armnn::TensorInfo recurrentToOutputWeightsInfo(recurrentToOutputWeightsShape,
4365                                                    armnn::DataType::QAsymmU8,
4366                                                    weightsScale,
4367                                                    weightsOffset);
4368     armnn::ConstTensor recurrentToOutputWeights(recurrentToOutputWeightsInfo, recurrentToOutputWeightsData);
4369
4370     // The shape of bias data is {outputSize} = {4}
4371     armnn::TensorShape inputGateBiasShape = {4};
4372     std::vector<int32_t> inputGateBiasData = {1, 2, 3, 4};
4373     armnn::TensorInfo inputGateBiasInfo(inputGateBiasShape,
4374                                         armnn::DataType::Signed32,
4375                                         biasScale,
4376                                         biasOffset);
4377     armnn::ConstTensor inputGateBias(inputGateBiasInfo, inputGateBiasData);
4378
4379     armnn::TensorShape forgetGateBiasShape = {4};
4380     std::vector<int32_t> forgetGateBiasData = {1, 2, 3, 4};
4381     armnn::TensorInfo forgetGateBiasInfo(forgetGateBiasShape,
4382                                          armnn::DataType::Signed32,
4383                                          biasScale,
4384                                          biasOffset);
4385     armnn::ConstTensor forgetGateBias(forgetGateBiasInfo, forgetGateBiasData);
4386
4387     armnn::TensorShape cellBiasShape = {4};
4388     std::vector<int32_t> cellBiasData = {1, 2, 3, 4};
4389     armnn::TensorInfo cellBiasInfo(cellBiasShape,
4390                                    armnn::DataType::Signed32,
4391                                    biasScale,
4392                                    biasOffset);
4393     armnn::ConstTensor cellBias(cellBiasInfo, cellBiasData);
4394
4395     armnn::TensorShape outputGateBiasShape = {4};
4396     std::vector<int32_t> outputGateBiasData = {1, 2, 3, 4};
4397     armnn::TensorInfo outputGateBiasInfo(outputGateBiasShape,
4398                                          armnn::DataType::Signed32,
4399                                          biasScale,
4400                                          biasOffset);
4401     armnn::ConstTensor outputGateBias(outputGateBiasInfo, outputGateBiasData);
4402
4403     armnn::QuantizedLstmInputParams params;
4404     params.m_InputToInputWeights = &inputToInputWeights;
4405     params.m_InputToForgetWeights = &inputToForgetWeights;
4406     params.m_InputToCellWeights = &inputToCellWeights;
4407     params.m_InputToOutputWeights = &inputToOutputWeights;
4408     params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4409     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4410     params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4411     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4412     params.m_InputGateBias = &inputGateBias;
4413     params.m_ForgetGateBias = &forgetGateBias;
4414     params.m_CellBias = &cellBias;
4415     params.m_OutputGateBias = &outputGateBias;
4416
4417     armnn::INetworkPtr network = armnn::INetwork::Create();
4418     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
4419     armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
4420     armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
4421     const std::string layerName("QuantizedLstm");
4422     armnn::IConnectableLayer* const quantizedLstmLayer = network->AddQuantizedLstmLayer(params, layerName.c_str());
4423     armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(0);
4424     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(1);
4425
4426     // Connect up
4427     armnn::TensorInfo inputTensorInfo({ batchSize, inputSize },
4428                                       armnn::DataType::QAsymmU8,
4429                                       inputOutputScale,
4430                                       inputOutputOffset);
4431     armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits },
4432                                           armnn::DataType::QSymmS16,
4433                                           cellStateScale,
4434                                           cellStateOffset);
4435     armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize },
4436                                             armnn::DataType::QAsymmU8,
4437                                             inputOutputScale,
4438                                             inputOutputOffset);
4439
4440     inputLayer->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(0));
4441     inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
4442
4443     cellStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(1));
4444     cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4445
4446     outputStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(2));
4447     outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
4448
4449     quantizedLstmLayer->GetOutputSlot(0).Connect(cellStateOut->GetInputSlot(0));
4450     quantizedLstmLayer->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4451
4452     quantizedLstmLayer->GetOutputSlot(1).Connect(outputLayer->GetInputSlot(0));
4453     quantizedLstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
4454
4455     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4456     BOOST_CHECK(deserializedNetwork);
4457
4458     VerifyQuantizedLstmLayer checker(layerName,
4459                                      {inputTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4460                                      {cellStateTensorInfo, outputStateTensorInfo},
4461                                      params);
4462
4463     deserializedNetwork->Accept(checker);
4464 }
4465
4466 class VerifyQLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>
4467 {
4468 public:
4469     VerifyQLstmLayer(const std::string& layerName,
4470                      const std::vector<armnn::TensorInfo>& inputInfos,
4471                      const std::vector<armnn::TensorInfo>& outputInfos,
4472                      const armnn::QLstmDescriptor& descriptor,
4473                      const armnn::LstmInputParams& inputParams)
4474         : LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
4475         , m_InputParams(inputParams) {}
4476
4477     void VisitQLstmLayer(const armnn::IConnectableLayer* layer,
4478                          const armnn::QLstmDescriptor& descriptor,
4479                          const armnn::LstmInputParams& params,
4480                          const char* name)
4481     {
4482         VerifyNameAndConnections(layer, name);
4483         VerifyDescriptor(descriptor);
4484         VerifyInputParameters(params);
4485     }
4486
4487 protected:
4488     void VerifyInputParameters(const armnn::LstmInputParams& params)
4489     {
4490         VerifyConstTensors(
4491             "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4492         VerifyConstTensors(
4493             "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4494         VerifyConstTensors(
4495             "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4496         VerifyConstTensors(
4497             "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4498         VerifyConstTensors(
4499             "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4500         VerifyConstTensors(
4501             "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4502         VerifyConstTensors(
4503             "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4504         VerifyConstTensors(
4505             "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4506         VerifyConstTensors(
4507             "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
4508         VerifyConstTensors(
4509             "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
4510         VerifyConstTensors(
4511             "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
4512         VerifyConstTensors(
4513             "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
4514         VerifyConstTensors(
4515             "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4516         VerifyConstTensors(
4517             "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
4518         VerifyConstTensors(
4519             "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4520         VerifyConstTensors(
4521             "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
4522         VerifyConstTensors(
4523             "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
4524         VerifyConstTensors(
4525             "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
4526         VerifyConstTensors(
4527             "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
4528         VerifyConstTensors(
4529             "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
4530         VerifyConstTensors(
4531             "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
4532     }
4533
4534 private:
4535     armnn::LstmInputParams m_InputParams;
4536 };
4537
4538 BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmBasic)
4539 {
4540     armnn::QLstmDescriptor descriptor;
4541
4542     descriptor.m_CifgEnabled       = true;
4543     descriptor.m_ProjectionEnabled = false;
4544     descriptor.m_PeepholeEnabled   = false;
4545     descriptor.m_LayerNormEnabled  = false;
4546
4547     descriptor.m_CellClip       = 0.0f;
4548     descriptor.m_ProjectionClip = 0.0f;
4549
4550     descriptor.m_InputIntermediateScale  = 0.00001f;
4551     descriptor.m_ForgetIntermediateScale = 0.00001f;
4552     descriptor.m_CellIntermediateScale   = 0.00001f;
4553     descriptor.m_OutputIntermediateScale = 0.00001f;
4554
4555     descriptor.m_HiddenStateScale     = 0.07f;
4556     descriptor.m_HiddenStateZeroPoint = 0;
4557
4558     const unsigned int numBatches = 2;
4559     const unsigned int inputSize  = 5;
4560     const unsigned int outputSize = 4;
4561     const unsigned int numUnits   = 4;
4562
4563     // Scale/Offset quantization info
4564     float inputScale    = 0.0078f;
4565     int32_t inputOffset = 0;
4566
4567     float outputScale    = 0.0078f;
4568     int32_t outputOffset = 0;
4569
4570     float cellStateScale    = 3.5002e-05f;
4571     int32_t cellStateOffset = 0;
4572
4573     float weightsScale    = 0.007f;
4574     int32_t weightsOffset = 0;
4575
4576     float biasScale    = 3.5002e-05f / 1024;
4577     int32_t biasOffset = 0;
4578
4579     // Weights and bias tensor and quantization info
4580     armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4581                                        armnn::DataType::QSymmS8,
4582                                        weightsScale,
4583                                        weightsOffset);
4584
4585     armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4586                                            armnn::DataType::QSymmS8,
4587                                            weightsScale,
4588                                            weightsOffset);
4589
4590     armnn::TensorInfo biasInfo({numUnits}, armnn::DataType::Signed32, biasScale, biasOffset);
4591
4592     std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4593     std::vector<int8_t> inputToCellWeightsData   = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4594     std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4595
4596     armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4597     armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4598     armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4599
4600     std::vector<int8_t> recurrentToForgetWeightsData =
4601             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4602     std::vector<int8_t> recurrentToCellWeightsData   =
4603             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4604     std::vector<int8_t> recurrentToOutputWeightsData =
4605             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4606
4607     armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4608     armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4609     armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4610
4611     std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4612     std::vector<int32_t> cellBiasData(numUnits, 0);
4613     std::vector<int32_t> outputGateBiasData(numUnits, 0);
4614
4615     armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4616     armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4617     armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4618
4619     // Set up params
4620     armnn::LstmInputParams params;
4621     params.m_InputToForgetWeights = &inputToForgetWeights;
4622     params.m_InputToCellWeights   = &inputToCellWeights;
4623     params.m_InputToOutputWeights = &inputToOutputWeights;
4624
4625     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4626     params.m_RecurrentToCellWeights   = &recurrentToCellWeights;
4627     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4628
4629     params.m_ForgetGateBias = &forgetGateBias;
4630     params.m_CellBias       = &cellBias;
4631     params.m_OutputGateBias = &outputGateBias;
4632
4633     // Create network
4634     armnn::INetworkPtr network = armnn::INetwork::Create();
4635     const std::string layerName("qLstm");
4636
4637     armnn::IConnectableLayer* const input         = network->AddInputLayer(0);
4638     armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4639     armnn::IConnectableLayer* const cellStateIn   = network->AddInputLayer(2);
4640
4641     armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4642
4643     armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4644     armnn::IConnectableLayer* const cellStateOut   = network->AddOutputLayer(1);
4645     armnn::IConnectableLayer* const outputLayer    = network->AddOutputLayer(2);
4646
4647     // Input/Output tensor info
4648     armnn::TensorInfo inputInfo({numBatches , inputSize},
4649                                 armnn::DataType::QAsymmS8,
4650                                 inputScale,
4651                                 inputOffset);
4652
4653     armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4654                                     armnn::DataType::QSymmS16,
4655                                     cellStateScale,
4656                                     cellStateOffset);
4657
4658     armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4659                                       armnn::DataType::QAsymmS8,
4660                                       outputScale,
4661                                       outputOffset);
4662
4663     // Connect input/output slots
4664     input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4665     input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4666
4667     outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4668     outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4669
4670     cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4671     cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4672
4673     qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4674     qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4675
4676     qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4677     qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4678
4679     qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4680     qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4681
4682     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4683     BOOST_CHECK(deserializedNetwork);
4684
4685     VerifyQLstmLayer checker(layerName,
4686                              {inputInfo, cellStateInfo, outputStateInfo},
4687                              {outputStateInfo, cellStateInfo, outputStateInfo},
4688                              descriptor,
4689                              params);
4690
4691     deserializedNetwork->Accept(checker);
4692 }
4693
4694 BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmCifgLayerNorm)
4695 {
4696     armnn::QLstmDescriptor descriptor;
4697
4698     // CIFG params are used when CIFG is disabled
4699     descriptor.m_CifgEnabled       = true;
4700     descriptor.m_ProjectionEnabled = false;
4701     descriptor.m_PeepholeEnabled   = false;
4702     descriptor.m_LayerNormEnabled  = true;
4703
4704     descriptor.m_CellClip       = 0.0f;
4705     descriptor.m_ProjectionClip = 0.0f;
4706
4707     descriptor.m_InputIntermediateScale  = 0.00001f;
4708     descriptor.m_ForgetIntermediateScale = 0.00001f;
4709     descriptor.m_CellIntermediateScale   = 0.00001f;
4710     descriptor.m_OutputIntermediateScale = 0.00001f;
4711
4712     descriptor.m_HiddenStateScale     = 0.07f;
4713     descriptor.m_HiddenStateZeroPoint = 0;
4714
4715     const unsigned int numBatches = 2;
4716     const unsigned int inputSize  = 5;
4717     const unsigned int outputSize = 4;
4718     const unsigned int numUnits   = 4;
4719
4720     // Scale/Offset quantization info
4721     float inputScale    = 0.0078f;
4722     int32_t inputOffset = 0;
4723
4724     float outputScale    = 0.0078f;
4725     int32_t outputOffset = 0;
4726
4727     float cellStateScale    = 3.5002e-05f;
4728     int32_t cellStateOffset = 0;
4729
4730     float weightsScale    = 0.007f;
4731     int32_t weightsOffset = 0;
4732
4733     float layerNormScale    = 3.5002e-05f;
4734     int32_t layerNormOffset = 0;
4735
4736     float biasScale    = layerNormScale / 1024;
4737     int32_t biasOffset = 0;
4738
4739     // Weights and bias tensor and quantization info
4740     armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4741                                        armnn::DataType::QSymmS8,
4742                                        weightsScale,
4743                                        weightsOffset);
4744
4745     armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4746                                            armnn::DataType::QSymmS8,
4747                                            weightsScale,
4748                                            weightsOffset);
4749
4750     armnn::TensorInfo biasInfo({numUnits},
4751                                armnn::DataType::Signed32,
4752                                biasScale,
4753                                biasOffset);
4754
4755     armnn::TensorInfo layerNormWeightsInfo({numUnits},
4756                                            armnn::DataType::QSymmS16,
4757                                            layerNormScale,
4758                                            layerNormOffset);
4759
4760     // Mandatory params
4761     std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4762     std::vector<int8_t> inputToCellWeightsData   = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4763     std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4764
4765     armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4766     armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4767     armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4768
4769     std::vector<int8_t> recurrentToForgetWeightsData =
4770             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4771     std::vector<int8_t> recurrentToCellWeightsData   =
4772             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4773     std::vector<int8_t> recurrentToOutputWeightsData =
4774             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4775
4776     armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4777     armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4778     armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4779
4780     std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4781     std::vector<int32_t> cellBiasData(numUnits, 0);
4782     std::vector<int32_t> outputGateBiasData(numUnits, 0);
4783
4784     armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4785     armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4786     armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4787
4788     // Layer Norm
4789     std::vector<int16_t> forgetLayerNormWeightsData =
4790             GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4791     std::vector<int16_t> cellLayerNormWeightsData =
4792             GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4793     std::vector<int16_t> outputLayerNormWeightsData =
4794             GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4795
4796     armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
4797     armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
4798     armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
4799
4800     // Set up params
4801     armnn::LstmInputParams params;
4802
4803     // Mandatory params
4804     params.m_InputToForgetWeights = &inputToForgetWeights;
4805     params.m_InputToCellWeights   = &inputToCellWeights;
4806     params.m_InputToOutputWeights = &inputToOutputWeights;
4807
4808     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4809     params.m_RecurrentToCellWeights   = &recurrentToCellWeights;
4810     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4811
4812     params.m_ForgetGateBias = &forgetGateBias;
4813     params.m_CellBias       = &cellBias;
4814     params.m_OutputGateBias = &outputGateBias;
4815
4816     // Layer Norm
4817     params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
4818     params.m_CellLayerNormWeights   = &cellLayerNormWeights;
4819     params.m_OutputLayerNormWeights = &outputLayerNormWeights;
4820
4821     // Create network
4822     armnn::INetworkPtr network = armnn::INetwork::Create();
4823     const std::string layerName("qLstm");
4824
4825     armnn::IConnectableLayer* const input         = network->AddInputLayer(0);
4826     armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4827     armnn::IConnectableLayer* const cellStateIn   = network->AddInputLayer(2);
4828
4829     armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4830
4831     armnn::IConnectableLayer* const outputStateOut  = network->AddOutputLayer(0);
4832     armnn::IConnectableLayer* const cellStateOut  = network->AddOutputLayer(1);
4833     armnn::IConnectableLayer* const outputLayer  = network->AddOutputLayer(2);
4834
4835     // Input/Output tensor info
4836     armnn::TensorInfo inputInfo({numBatches , inputSize},
4837                                 armnn::DataType::QAsymmS8,
4838                                 inputScale,
4839                                 inputOffset);
4840
4841     armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4842                                     armnn::DataType::QSymmS16,
4843                                     cellStateScale,
4844                                     cellStateOffset);
4845
4846     armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4847                                       armnn::DataType::QAsymmS8,
4848                                       outputScale,
4849                                       outputOffset);
4850
4851     // Connect input/output slots
4852     input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4853     input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4854
4855     outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4856     outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4857
4858     cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4859     cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4860
4861     qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4862     qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4863
4864     qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4865     qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4866
4867     qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4868     qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4869
4870     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4871     BOOST_CHECK(deserializedNetwork);
4872
4873     VerifyQLstmLayer checker(layerName,
4874                              {inputInfo, cellStateInfo, outputStateInfo},
4875                              {outputStateInfo, cellStateInfo, outputStateInfo},
4876                              descriptor,
4877                              params);
4878
4879     deserializedNetwork->Accept(checker);
4880 }
4881
4882 BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmAdvanced)
4883 {
4884     armnn::QLstmDescriptor descriptor;
4885
4886     descriptor.m_CifgEnabled       = false;
4887     descriptor.m_ProjectionEnabled = true;
4888     descriptor.m_PeepholeEnabled   = true;
4889     descriptor.m_LayerNormEnabled  = true;
4890
4891     descriptor.m_CellClip       = 0.1f;
4892     descriptor.m_ProjectionClip = 0.1f;
4893
4894     descriptor.m_InputIntermediateScale  = 0.00001f;
4895     descriptor.m_ForgetIntermediateScale = 0.00001f;
4896     descriptor.m_CellIntermediateScale   = 0.00001f;
4897     descriptor.m_OutputIntermediateScale = 0.00001f;
4898
4899     descriptor.m_HiddenStateScale     = 0.07f;
4900     descriptor.m_HiddenStateZeroPoint = 0;
4901
4902     const unsigned int numBatches = 2;
4903     const unsigned int inputSize  = 5;
4904     const unsigned int outputSize = 4;
4905     const unsigned int numUnits   = 4;
4906
4907     // Scale/Offset quantization info
4908     float inputScale    = 0.0078f;
4909     int32_t inputOffset = 0;
4910
4911     float outputScale    = 0.0078f;
4912     int32_t outputOffset = 0;
4913
4914     float cellStateScale    = 3.5002e-05f;
4915     int32_t cellStateOffset = 0;
4916
4917     float weightsScale    = 0.007f;
4918     int32_t weightsOffset = 0;
4919
4920     float layerNormScale    = 3.5002e-05f;
4921     int32_t layerNormOffset = 0;
4922
4923     float biasScale    = layerNormScale / 1024;
4924     int32_t biasOffset = 0;
4925
4926     // Weights and bias tensor and quantization info
4927     armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4928                                        armnn::DataType::QSymmS8,
4929                                        weightsScale,
4930                                        weightsOffset);
4931
4932     armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4933                                            armnn::DataType::QSymmS8,
4934                                            weightsScale,
4935                                            weightsOffset);
4936
4937     armnn::TensorInfo biasInfo({numUnits},
4938                                armnn::DataType::Signed32,
4939                                biasScale,
4940                                biasOffset);
4941
4942     armnn::TensorInfo peepholeWeightsInfo({numUnits},
4943                                           armnn::DataType::QSymmS16,
4944                                           weightsScale,
4945                                           weightsOffset);
4946
4947     armnn::TensorInfo layerNormWeightsInfo({numUnits},
4948                                            armnn::DataType::QSymmS16,
4949                                            layerNormScale,
4950                                            layerNormOffset);
4951
4952     armnn::TensorInfo projectionWeightsInfo({outputSize, numUnits},
4953                                              armnn::DataType::QSymmS8,
4954                                              weightsScale,
4955                                              weightsOffset);
4956
4957     // Mandatory params
4958     std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4959     std::vector<int8_t> inputToCellWeightsData   = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4960     std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4961
4962     armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4963     armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4964     armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4965
4966     std::vector<int8_t> recurrentToForgetWeightsData =
4967             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4968     std::vector<int8_t> recurrentToCellWeightsData   =
4969             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4970     std::vector<int8_t> recurrentToOutputWeightsData =
4971             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4972
4973     armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4974     armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4975     armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4976
4977     std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4978     std::vector<int32_t> cellBiasData(numUnits, 0);
4979     std::vector<int32_t> outputGateBiasData(numUnits, 0);
4980
4981     armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4982     armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4983     armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4984
4985     // CIFG
4986     std::vector<int8_t> inputToInputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4987     std::vector<int8_t> recurrentToInputWeightsData =
4988             GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4989     std::vector<int32_t> inputGateBiasData(numUnits, 1);
4990
4991     armnn::ConstTensor inputToInputWeights(inputWeightsInfo, inputToInputWeightsData);
4992     armnn::ConstTensor recurrentToInputWeights(recurrentWeightsInfo, recurrentToInputWeightsData);
4993     armnn::ConstTensor inputGateBias(biasInfo, inputGateBiasData);
4994
4995     // Peephole
4996     std::vector<int16_t> cellToInputWeightsData  = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4997     std::vector<int16_t> cellToForgetWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4998     std::vector<int16_t> cellToOutputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4999
5000     armnn::ConstTensor cellToInputWeights(peepholeWeightsInfo, cellToInputWeightsData);
5001     armnn::ConstTensor cellToForgetWeights(peepholeWeightsInfo, cellToForgetWeightsData);
5002     armnn::ConstTensor cellToOutputWeights(peepholeWeightsInfo, cellToOutputWeightsData);
5003
5004     // Projection
5005     std::vector<int8_t> projectionWeightsData = GenerateRandomData<int8_t>(projectionWeightsInfo.GetNumElements());
5006     std::vector<int32_t> projectionBiasData(outputSize, 1);
5007
5008     armnn::ConstTensor projectionWeights(projectionWeightsInfo, projectionWeightsData);
5009     armnn::ConstTensor projectionBias(biasInfo, projectionBiasData);
5010
5011     // Layer Norm
5012     std::vector<int16_t> inputLayerNormWeightsData =
5013             GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5014     std::vector<int16_t> forgetLayerNormWeightsData =
5015             GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5016     std::vector<int16_t> cellLayerNormWeightsData =
5017             GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5018     std::vector<int16_t> outputLayerNormWeightsData =
5019             GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5020
5021     armnn::ConstTensor inputLayerNormWeights(layerNormWeightsInfo, inputLayerNormWeightsData);
5022     armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
5023     armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
5024     armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
5025
5026     // Set up params
5027     armnn::LstmInputParams params;
5028
5029     // Mandatory params
5030     params.m_InputToForgetWeights = &inputToForgetWeights;
5031     params.m_InputToCellWeights   = &inputToCellWeights;
5032     params.m_InputToOutputWeights = &inputToOutputWeights;
5033
5034     params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
5035     params.m_RecurrentToCellWeights   = &recurrentToCellWeights;
5036     params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
5037
5038     params.m_ForgetGateBias = &forgetGateBias;
5039     params.m_CellBias       = &cellBias;
5040     params.m_OutputGateBias = &outputGateBias;
5041
5042     // CIFG
5043     params.m_InputToInputWeights     = &inputToInputWeights;
5044     params.m_RecurrentToInputWeights = &recurrentToInputWeights;
5045     params.m_InputGateBias           = &inputGateBias;
5046
5047     // Peephole
5048     params.m_CellToInputWeights  = &cellToInputWeights;
5049     params.m_CellToForgetWeights = &cellToForgetWeights;
5050     params.m_CellToOutputWeights = &cellToOutputWeights;
5051
5052     // Projection
5053     params.m_ProjectionWeights = &projectionWeights;
5054     params.m_ProjectionBias    = &projectionBias;
5055
5056     // Layer Norm
5057     params.m_InputLayerNormWeights  = &inputLayerNormWeights;
5058     params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
5059     params.m_CellLayerNormWeights   = &cellLayerNormWeights;
5060     params.m_OutputLayerNormWeights = &outputLayerNormWeights;
5061
5062     // Create network
5063     armnn::INetworkPtr network = armnn::INetwork::Create();
5064     const std::string layerName("qLstm");
5065
5066     armnn::IConnectableLayer* const input         = network->AddInputLayer(0);
5067     armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
5068     armnn::IConnectableLayer* const cellStateIn   = network->AddInputLayer(2);
5069
5070     armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
5071
5072     armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
5073     armnn::IConnectableLayer* const cellStateOut   = network->AddOutputLayer(1);
5074     armnn::IConnectableLayer* const outputLayer    = network->AddOutputLayer(2);
5075
5076     // Input/Output tensor info
5077     armnn::TensorInfo inputInfo({numBatches , inputSize},
5078                                 armnn::DataType::QAsymmS8,
5079                                 inputScale,
5080                                 inputOffset);
5081
5082     armnn::TensorInfo cellStateInfo({numBatches , numUnits},
5083                                     armnn::DataType::QSymmS16,
5084                                     cellStateScale,
5085                                     cellStateOffset);
5086
5087     armnn::TensorInfo outputStateInfo({numBatches , outputSize},
5088                                       armnn::DataType::QAsymmS8,
5089                                       outputScale,
5090                                       outputOffset);
5091
5092     // Connect input/output slots
5093     input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
5094     input->GetOutputSlot(0).SetTensorInfo(inputInfo);
5095
5096     outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
5097     outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
5098
5099     cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
5100     cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
5101
5102     qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
5103     qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
5104
5105     qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
5106     qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
5107
5108     qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
5109     qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
5110
5111     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
5112     BOOST_CHECK(deserializedNetwork);
5113
5114     VerifyQLstmLayer checker(layerName,
5115                              {inputInfo, cellStateInfo, outputStateInfo},
5116                              {outputStateInfo, cellStateInfo, outputStateInfo},
5117                              descriptor,
5118                              params);
5119
5120     deserializedNetwork->Accept(checker);
5121 }
5122
5123 BOOST_AUTO_TEST_SUITE_END()