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