ArmNN
 20.05
SerializerTests.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. 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>
14 
15 #include <random>
16 #include <vector>
17 
18 #include <boost/test/unit_test.hpp>
19 
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  {
209  CompareConstTensorData<const float*>(
210  tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
211  break;
214  CompareConstTensorData<const uint8_t*>(
215  tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
216  break;
218  CompareConstTensorData<const int8_t*>(
219  tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
220  break;
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 {
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 {
278 
279  const std::string layerName("addition");
280  const armnn::TensorInfo tensorInfo({1, 2, 3}, armnn::DataType::Float32);
281 
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 {
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;
313  descriptor.m_Axis = 1;
314 
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 
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 
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 {
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 
430  desc.m_BlockShape = {2, 2};
431  desc.m_Crops = {{0, 0}, {0, 0}};
432 
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 {
454 
455  const std::string layerName("comparison");
456 
457  const armnn::TensorShape shape{2, 1, 2, 4};
458 
461 
463 
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 
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,
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,
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;
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 
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;
605 
607  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
608  armnn::IConnectableLayer* const convLayer =
609  network->AddConvolution2dLayer(descriptor,
610  weights,
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,
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,
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;
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;
699 
701  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
702  armnn::IConnectableLayer* const convLayer =
703  network->AddConvolution2dLayer(descriptor,
704  weights,
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 {
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 
732  desc.m_BlockSize = 2;
733  desc.m_DataLayout = armnn::DataLayout::NHWC;
734 
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,
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;
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 
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;
820 
822  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
823  armnn::IConnectableLayer* const depthwiseConvLayer =
824  network->AddDepthwiseConvolution2dLayer(descriptor,
825  weights,
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,
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;
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 
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;
916 
918  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
919  armnn::IConnectableLayer* const depthwiseConvLayer =
920  network->AddDepthwiseConvolution2dLayer(descriptor,
921  weights,
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 {
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 
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,
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({
999  });
1000 
1001  const std::vector<armnn::TensorInfo> outputInfos({
1006  });
1007 
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 
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 
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 {
1060 
1061  const std::string layerName("division");
1062  const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1063 
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);
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 
1118 
1120  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1121  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1123  armnn::IConnectableLayer* const equalLayer = network->AddEqualLayer(layerName.c_str());
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 
1197 
1198  EqualLayerVerifier verifier("equal", { inputInfo, inputInfo }, { outputInfo });
1199  deserializedNetwork->Accept(verifier);
1200 }
1201 
1202 BOOST_AUTO_TEST_CASE(SerializeFloor)
1203 {
1205 
1206  const std::string layerName("floor");
1208 
1210  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1211  armnn::IConnectableLayer* const floorLayer = network->AddFloorLayer(layerName.c_str());
1212  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1213 
1214  inputLayer->GetOutputSlot(0).Connect(floorLayer->GetInputSlot(0));
1215  floorLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1216 
1217  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1218  floorLayer->GetOutputSlot(0).SetTensorInfo(info);
1219 
1220  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1221  BOOST_CHECK(deserializedNetwork);
1222 
1223  FloorLayerVerifier verifier(layerName, {info}, {info});
1224  deserializedNetwork->Accept(verifier);
1225 }
1226 
1227 BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
1228 {
1229  using Descriptor = armnn::FullyConnectedDescriptor;
1230  class FullyConnectedLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
1231  {
1232  public:
1233  FullyConnectedLayerVerifier(const std::string& layerName,
1234  const std::vector<armnn::TensorInfo>& inputInfos,
1235  const std::vector<armnn::TensorInfo>& outputInfos,
1236  const Descriptor& descriptor,
1237  const armnn::ConstTensor& weight,
1239  : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
1240  , m_Weight(weight)
1241  , m_Bias(bias) {}
1242 
1243  void VisitFullyConnectedLayer(const armnn::IConnectableLayer* layer,
1244  const Descriptor& descriptor,
1245  const armnn::ConstTensor& weight,
1247  const char* name) override
1248  {
1249  VerifyNameAndConnections(layer, name);
1250  VerifyDescriptor(descriptor);
1251 
1252  CompareConstTensor(weight, m_Weight);
1253 
1254  BOOST_TEST(bias.has_value() == descriptor.m_BiasEnabled);
1255  BOOST_TEST(bias.has_value() == m_Bias.has_value());
1256 
1257  if (bias.has_value() && m_Bias.has_value())
1258  {
1259  CompareConstTensor(bias.value(), m_Bias.value());
1260  }
1261  }
1262 
1263  private:
1264  armnn::ConstTensor m_Weight;
1266  };
1267 
1268  const std::string layerName("fullyConnected");
1269  const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
1270  const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
1271 
1272  const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
1273  const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
1274  std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
1275  std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
1276  armnn::ConstTensor weights(weightsInfo, weightsData);
1277  armnn::ConstTensor biases(biasesInfo, biasesData);
1278 
1280  descriptor.m_BiasEnabled = true;
1281  descriptor.m_TransposeWeightMatrix = false;
1282 
1284  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1285  armnn::IConnectableLayer* const fullyConnectedLayer =
1286  network->AddFullyConnectedLayer(descriptor,
1287  weights,
1289  layerName.c_str());
1290  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1291 
1292  inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
1293  fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1294 
1295  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1296  fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1297 
1298  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1299  BOOST_CHECK(deserializedNetwork);
1300 
1301  FullyConnectedLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
1302  deserializedNetwork->Accept(verifier);
1303 }
1304 
1305 BOOST_AUTO_TEST_CASE(SerializeGather)
1306 {
1307  class GatherLayerVerifier : public LayerVerifierBase
1308  {
1309  public:
1310  GatherLayerVerifier(const std::string& layerName,
1311  const std::vector<armnn::TensorInfo>& inputInfos,
1312  const std::vector<armnn::TensorInfo>& outputInfos)
1313  : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1314 
1315  void VisitGatherLayer(const armnn::IConnectableLayer* layer, const char *name) override
1316  {
1317  VerifyNameAndConnections(layer, name);
1318  }
1319 
1320  void VisitConstantLayer(const armnn::IConnectableLayer*,
1321  const armnn::ConstTensor&,
1322  const char*) override {}
1323  };
1324 
1325  const std::string layerName("gather");
1326  armnn::TensorInfo paramsInfo({ 8 }, armnn::DataType::QAsymmU8);
1327  armnn::TensorInfo outputInfo({ 3 }, armnn::DataType::QAsymmU8);
1328  const armnn::TensorInfo indicesInfo({ 3 }, armnn::DataType::Signed32);
1329 
1330  paramsInfo.SetQuantizationScale(1.0f);
1331  paramsInfo.SetQuantizationOffset(0);
1332  outputInfo.SetQuantizationScale(1.0f);
1333  outputInfo.SetQuantizationOffset(0);
1334 
1335  const std::vector<int32_t>& indicesData = {7, 6, 5};
1336 
1338  armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
1339  armnn::IConnectableLayer *const constantLayer =
1340  network->AddConstantLayer(armnn::ConstTensor(indicesInfo, indicesData));
1341  armnn::IConnectableLayer *const gatherLayer = network->AddGatherLayer(layerName.c_str());
1342  armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
1343 
1344  inputLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(0));
1345  constantLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(1));
1346  gatherLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1347 
1348  inputLayer->GetOutputSlot(0).SetTensorInfo(paramsInfo);
1349  constantLayer->GetOutputSlot(0).SetTensorInfo(indicesInfo);
1350  gatherLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1351 
1352  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1353  BOOST_CHECK(deserializedNetwork);
1354 
1355  GatherLayerVerifier verifier(layerName, {paramsInfo, indicesInfo}, {outputInfo});
1356  deserializedNetwork->Accept(verifier);
1357 }
1358 
1359 class GreaterLayerVerifier : public LayerVerifierBase
1360 {
1361 public:
1362  GreaterLayerVerifier(const std::string& layerName,
1363  const std::vector<armnn::TensorInfo>& inputInfos,
1364  const std::vector<armnn::TensorInfo>& outputInfos)
1365  : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1366 
1367  void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1368  const armnn::ComparisonDescriptor& descriptor,
1369  const char* name) override
1370  {
1371  VerifyNameAndConnections(layer, name);
1373  }
1374 
1375  void VisitGreaterLayer(const armnn::IConnectableLayer*, const char*) override
1376  {
1377  throw armnn::Exception("GreaterLayer should have translated to ComparisonLayer");
1378  }
1379 };
1380 
1381 // NOTE: Until the deprecated AddGreaterLayer disappears this test checks that calling
1382 // AddGreaterLayer places a ComparisonLayer into the serialized format and that
1383 // when this deserialises we have a ComparisonLayer
1384 BOOST_AUTO_TEST_CASE(SerializeGreater)
1385 {
1386  const std::string layerName("greater");
1387 
1388  const armnn::TensorShape shape{2, 1, 2, 4};
1389 
1392 
1394  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1395  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1397  armnn::IConnectableLayer* const equalLayer = network->AddGreaterLayer(layerName.c_str());
1399  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1400 
1401  inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1402  inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1403  equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1404 
1405  inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1406  inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1407  equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1408 
1409  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1410  BOOST_CHECK(deserializedNetwork);
1411 
1412  GreaterLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1413  deserializedNetwork->Accept(verifier);
1414 }
1415 
1416 BOOST_AUTO_TEST_CASE(EnsureGreaterBackwardCompatibility)
1417 {
1418  // The hex data below is a flat buffer containing a simple network with two inputs,
1419  // an GreaterLayer (now deprecated) and an output
1420  //
1421  // This test verifies that we can still deserialize this old-style model by replacing
1422  // the GreaterLayer with an equivalent ComparisonLayer
1423  const std::vector<uint8_t> greaterModel =
1424  {
1425  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1426  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1427  0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1428  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1429  0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1430  0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1431  0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1432  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1433  0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1434  0x00, 0x19, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1435  0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1436  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x00, 0x02, 0x00, 0x00, 0x00,
1437  0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1438  0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1439  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1440  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1441  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1442  0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1443  0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1444  0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1445  0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1446  0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1447  0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1448  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1449  0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1450  0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1451  0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1452  0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1453  0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1454  0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1455  0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1456  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1457  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1458  0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1459  0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1460  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1461  0x02, 0x00, 0x00, 0x00
1462  };
1463 
1464  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(greaterModel.begin(), greaterModel.end()));
1465  BOOST_CHECK(deserializedNetwork);
1466 
1467  const armnn::TensorShape shape{ 1, 2, 2, 2 };
1468 
1471 
1472  GreaterLayerVerifier verifier("greater", { inputInfo, inputInfo }, { outputInfo });
1473  deserializedNetwork->Accept(verifier);
1474 }
1475 
1476 BOOST_AUTO_TEST_CASE(SerializeInstanceNormalization)
1477 {
1479 
1480  const std::string layerName("instanceNormalization");
1481  const armnn::TensorInfo info({ 1, 2, 1, 5 }, armnn::DataType::Float32);
1482 
1484  descriptor.m_Gamma = 1.1f;
1485  descriptor.m_Beta = 0.1f;
1486  descriptor.m_Eps = 0.0001f;
1487  descriptor.m_DataLayout = armnn::DataLayout::NHWC;
1488 
1490  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1491  armnn::IConnectableLayer* const instanceNormLayer =
1492  network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1493  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1494 
1495  inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1496  instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1497 
1498  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1499  instanceNormLayer->GetOutputSlot(0).SetTensorInfo(info);
1500 
1501  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1502  BOOST_CHECK(deserializedNetwork);
1503 
1504  InstanceNormalizationLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1505  deserializedNetwork->Accept(verifier);
1506 }
1507 
1509 
1510 BOOST_AUTO_TEST_CASE(SerializeL2Normalization)
1511 {
1512  const std::string l2NormLayerName("l2Normalization");
1513  const armnn::TensorInfo info({1, 2, 1, 5}, armnn::DataType::Float32);
1514 
1517  desc.m_Eps = 0.0001f;
1518 
1520  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1521  armnn::IConnectableLayer* const l2NormLayer = network->AddL2NormalizationLayer(desc, l2NormLayerName.c_str());
1522  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1523 
1524  inputLayer0->GetOutputSlot(0).Connect(l2NormLayer->GetInputSlot(0));
1525  l2NormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1526 
1527  inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1528  l2NormLayer->GetOutputSlot(0).SetTensorInfo(info);
1529 
1530  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1531  BOOST_CHECK(deserializedNetwork);
1532 
1533  L2NormalizationLayerVerifier verifier(l2NormLayerName, {info}, {info}, desc);
1534  deserializedNetwork->Accept(verifier);
1535 }
1536 
1537 BOOST_AUTO_TEST_CASE(EnsureL2NormalizationBackwardCompatibility)
1538 {
1539  // The hex data below is a flat buffer containing a simple network with one input
1540  // a L2Normalization layer and an output layer with dimensions as per the tensor infos below.
1541  //
1542  // This test verifies that we can still read back these old style
1543  // models without the normalization epsilon value.
1544  const std::vector<uint8_t> l2NormalizationModel =
1545  {
1546  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1547  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1548  0x3C, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1549  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
1550  0x04, 0x00, 0x00, 0x00, 0xD6, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
1551  0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
1552  0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1553  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1554  0x4C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1555  0x00, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1556  0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1557  0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1558  0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x20, 0x00,
1559  0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x6C, 0x32, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x61, 0x74,
1560  0x69, 0x6F, 0x6E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00,
1561  0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1562  0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
1563  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1564  0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1565  0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1566  0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1567  0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1568  0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1569  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1570  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1571  0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1572  0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1573  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1574  0x05, 0x00, 0x00, 0x00, 0x00
1575  };
1576 
1577  armnn::INetworkPtr deserializedNetwork =
1578  DeserializeNetwork(std::string(l2NormalizationModel.begin(), l2NormalizationModel.end()));
1579  BOOST_CHECK(deserializedNetwork);
1580 
1581  const std::string layerName("l2Normalization");
1582  const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 2, 1, 5}, armnn::DataType::Float32);
1583 
1586  // Since this variable does not exist in the l2NormalizationModel dump, the default value will be loaded
1587  desc.m_Eps = 1e-12f;
1588 
1589  L2NormalizationLayerVerifier verifier(layerName, {inputInfo}, {inputInfo}, desc);
1590  deserializedNetwork->Accept(verifier);
1591 }
1592 
1593 BOOST_AUTO_TEST_CASE(SerializeLogSoftmax)
1594 {
1596 
1597  const std::string layerName("log_softmax");
1599 
1600  armnn::LogSoftmaxDescriptor descriptor;
1601  descriptor.m_Beta = 1.0f;
1602  descriptor.m_Axis = -1;
1603 
1605  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1606  armnn::IConnectableLayer* const logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
1607  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1608 
1609  inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
1610  logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1611 
1612  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1613  logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
1614 
1615  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1616  BOOST_CHECK(deserializedNetwork);
1617 
1618  LogSoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1619  deserializedNetwork->Accept(verifier);
1620 }
1621 
1622 BOOST_AUTO_TEST_CASE(SerializeMaximum)
1623 {
1625 
1626  const std::string layerName("maximum");
1627  const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1628 
1630  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1631  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1632  armnn::IConnectableLayer* const maximumLayer = network->AddMaximumLayer(layerName.c_str());
1633  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1634 
1635  inputLayer0->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(0));
1636  inputLayer1->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(1));
1637  maximumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1638 
1639  inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1640  inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1641  maximumLayer->GetOutputSlot(0).SetTensorInfo(info);
1642 
1643  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1644  BOOST_CHECK(deserializedNetwork);
1645 
1646  MaximumLayerVerifier verifier(layerName, {info, info}, {info});
1647  deserializedNetwork->Accept(verifier);
1648 }
1649 
1650 BOOST_AUTO_TEST_CASE(SerializeMean)
1651 {
1653 
1654  const std::string layerName("mean");
1655  const armnn::TensorInfo inputInfo({1, 1, 3, 2}, armnn::DataType::Float32);
1656  const armnn::TensorInfo outputInfo({1, 1, 1, 2}, armnn::DataType::Float32);
1657 
1658  armnn::MeanDescriptor descriptor;
1659  descriptor.m_Axis = { 2 };
1660  descriptor.m_KeepDims = true;
1661 
1663  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1664  armnn::IConnectableLayer* const meanLayer = network->AddMeanLayer(descriptor, layerName.c_str());
1665  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1666 
1667  inputLayer->GetOutputSlot(0).Connect(meanLayer->GetInputSlot(0));
1668  meanLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1669 
1670  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1671  meanLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1672 
1673  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1674  BOOST_CHECK(deserializedNetwork);
1675 
1676  MeanLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1677  deserializedNetwork->Accept(verifier);
1678 }
1679 
1680 BOOST_AUTO_TEST_CASE(SerializeMerge)
1681 {
1683 
1684  const std::string layerName("merge");
1685  const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1686 
1688  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1689  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1690  armnn::IConnectableLayer* const mergeLayer = network->AddMergeLayer(layerName.c_str());
1691  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1692 
1693  inputLayer0->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(0));
1694  inputLayer1->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(1));
1695  mergeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1696 
1697  inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1698  inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1699  mergeLayer->GetOutputSlot(0).SetTensorInfo(info);
1700 
1701  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1702  BOOST_CHECK(deserializedNetwork);
1703 
1704  MergeLayerVerifier verifier(layerName, {info, info}, {info});
1705  deserializedNetwork->Accept(verifier);
1706 }
1707 
1708 class MergerLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>
1709 {
1710 public:
1711  MergerLayerVerifier(const std::string& layerName,
1712  const std::vector<armnn::TensorInfo>& inputInfos,
1713  const std::vector<armnn::TensorInfo>& outputInfos,
1714  const armnn::OriginsDescriptor& descriptor)
1715  : LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
1716 
1717  void VisitMergerLayer(const armnn::IConnectableLayer*,
1718  const armnn::OriginsDescriptor&,
1719  const char*) override
1720  {
1721  throw armnn::Exception("MergerLayer should have translated to ConcatLayer");
1722  }
1723 
1724  void VisitConcatLayer(const armnn::IConnectableLayer* layer,
1725  const armnn::OriginsDescriptor& descriptor,
1726  const char* name) override
1727  {
1728  VerifyNameAndConnections(layer, name);
1729  VerifyDescriptor(descriptor);
1730  }
1731 };
1732 
1733 // NOTE: Until the deprecated AddMergerLayer disappears this test checks that calling
1734 // AddMergerLayer places a ConcatLayer into the serialized format and that
1735 // when this deserialises we have a ConcatLayer
1736 BOOST_AUTO_TEST_CASE(SerializeMerger)
1737 {
1738  const std::string layerName("merger");
1739  const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1740  const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1741 
1742  const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1743 
1744  armnn::OriginsDescriptor descriptor =
1745  armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1746 
1748  armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1749  armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1751  armnn::IConnectableLayer* const mergerLayer = network->AddMergerLayer(descriptor, layerName.c_str());
1753  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1754 
1755  inputLayerOne->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0));
1756  inputLayerTwo->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1));
1757  mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1758 
1759  inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1760  inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1761  mergerLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1762 
1763  std::string mergerLayerNetwork = SerializeNetwork(*network);
1764  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(mergerLayerNetwork);
1765  BOOST_CHECK(deserializedNetwork);
1766 
1767  MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1768  deserializedNetwork->Accept(verifier);
1769 }
1770 
1771 BOOST_AUTO_TEST_CASE(EnsureMergerLayerBackwardCompatibility)
1772 {
1773  // The hex data below is a flat buffer containing a simple network with two inputs
1774  // a merger layer (now deprecated) and an output layer with dimensions as per the tensor infos below.
1775  //
1776  // This test verifies that we can still read back these old style
1777  // models replacing the MergerLayers with ConcatLayers with the same parameters.
1778  const std::vector<uint8_t> mergerModel =
1779  {
1780  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1781  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1782  0x38, 0x02, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1783  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1784  0xF4, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1785  0x00, 0x00, 0x9A, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1786  0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1787  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1788  0xF8, 0xFE, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1789  0x00, 0x1F, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1790  0x68, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
1791  0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1792  0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
1793  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1794  0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1795  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1796  0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1797  0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x72, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1798  0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1799  0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
1800  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00,
1801  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1802  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1803  0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1804  0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1805  0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1806  0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1807  0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1808  0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1809  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1810  0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1811  0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1812  0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1813  0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1814  0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1815  0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1816  0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1817  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1818  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1819  0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1820  0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1821  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1822  0x02, 0x00, 0x00, 0x00
1823  };
1824 
1825  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(mergerModel.begin(), mergerModel.end()));
1826  BOOST_CHECK(deserializedNetwork);
1827 
1828  const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 2, 3, 2, 2 }, armnn::DataType::Float32);
1829  const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 4, 3, 2, 2 }, armnn::DataType::Float32);
1830 
1831  const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1832 
1833  armnn::OriginsDescriptor descriptor =
1834  armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1835 
1836  MergerLayerVerifier verifier("merger", { inputInfo, inputInfo }, { outputInfo }, descriptor);
1837  deserializedNetwork->Accept(verifier);
1838 }
1839 
1840 BOOST_AUTO_TEST_CASE(SerializeConcat)
1841 {
1842  const std::string layerName("concat");
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 
1852  armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1853  armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1854  armnn::IConnectableLayer* const concatLayer = network->AddConcatLayer(descriptor, layerName.c_str());
1855  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1856 
1857  inputLayerOne->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
1858  inputLayerTwo->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
1859  concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1860 
1861  inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1862  inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1863  concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1864 
1865  std::string concatLayerNetwork = SerializeNetwork(*network);
1866  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(concatLayerNetwork);
1867  BOOST_CHECK(deserializedNetwork);
1868 
1869  // NOTE: using the MergerLayerVerifier to ensure that it is a concat layer and not a
1870  // merger layer that gets placed into the graph.
1871  MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1872  deserializedNetwork->Accept(verifier);
1873 }
1874 
1875 BOOST_AUTO_TEST_CASE(SerializeMinimum)
1876 {
1878 
1879  const std::string layerName("minimum");
1880  const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1881 
1883  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1884  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1885  armnn::IConnectableLayer* const minimumLayer = network->AddMinimumLayer(layerName.c_str());
1886  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1887 
1888  inputLayer0->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(0));
1889  inputLayer1->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(1));
1890  minimumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1891 
1892  inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1893  inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1894  minimumLayer->GetOutputSlot(0).SetTensorInfo(info);
1895 
1896  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1897  BOOST_CHECK(deserializedNetwork);
1898 
1899  MinimumLayerVerifier verifier(layerName, {info, info}, {info});
1900  deserializedNetwork->Accept(verifier);
1901 }
1902 
1903 BOOST_AUTO_TEST_CASE(SerializeMultiplication)
1904 {
1906 
1907  const std::string layerName("multiplication");
1908  const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1909 
1911  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1912  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1913  armnn::IConnectableLayer* const multiplicationLayer = network->AddMultiplicationLayer(layerName.c_str());
1914  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1915 
1916  inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(0));
1917  inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(1));
1918  multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1919 
1920  inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1921  inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1922  multiplicationLayer->GetOutputSlot(0).SetTensorInfo(info);
1923 
1924  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1925  BOOST_CHECK(deserializedNetwork);
1926 
1927  MultiplicationLayerVerifier verifier(layerName, {info, info}, {info});
1928  deserializedNetwork->Accept(verifier);
1929 }
1930 
1931 BOOST_AUTO_TEST_CASE(SerializePrelu)
1932 {
1934 
1935  const std::string layerName("prelu");
1936 
1937  armnn::TensorInfo inputTensorInfo ({ 4, 1, 2 }, armnn::DataType::Float32);
1938  armnn::TensorInfo alphaTensorInfo ({ 5, 4, 3, 1 }, armnn::DataType::Float32);
1939  armnn::TensorInfo outputTensorInfo({ 5, 4, 3, 2 }, armnn::DataType::Float32);
1940 
1942  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1943  armnn::IConnectableLayer* const alphaLayer = network->AddInputLayer(1);
1944  armnn::IConnectableLayer* const preluLayer = network->AddPreluLayer(layerName.c_str());
1945  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1946 
1947  inputLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(0));
1948  alphaLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(1));
1949  preluLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1950 
1951  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
1952  alphaLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
1953  preluLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1954 
1955  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1956  BOOST_CHECK(deserializedNetwork);
1957 
1958  PreluLayerVerifier verifier(layerName, {inputTensorInfo, alphaTensorInfo}, {outputTensorInfo});
1959  deserializedNetwork->Accept(verifier);
1960 }
1961 
1962 BOOST_AUTO_TEST_CASE(SerializeNormalization)
1963 {
1965 
1966  const std::string layerName("normalization");
1967  const armnn::TensorInfo info({2, 1, 2, 2}, armnn::DataType::Float32);
1968 
1971  desc.m_NormSize = 3;
1972  desc.m_Alpha = 1;
1973  desc.m_Beta = 1;
1974  desc.m_K = 1;
1975 
1977  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1978  armnn::IConnectableLayer* const normalizationLayer = network->AddNormalizationLayer(desc, layerName.c_str());
1979  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1980 
1981  inputLayer->GetOutputSlot(0).Connect(normalizationLayer->GetInputSlot(0));
1982  normalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1983 
1984  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1985  normalizationLayer->GetOutputSlot(0).SetTensorInfo(info);
1986 
1987  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1988  BOOST_CHECK(deserializedNetwork);
1989 
1990  NormalizationLayerVerifier verifier(layerName, {info}, {info}, desc);
1991  deserializedNetwork->Accept(verifier);
1992 }
1993 
1995 
1997 {
1998  const std::string layerName("pad");
1999  const armnn::TensorInfo inputTensorInfo = armnn::TensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2000  const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({1, 3, 5, 7}, armnn::DataType::Float32);
2001 
2002  armnn::PadDescriptor desc({{0, 0}, {1, 0}, {1, 1}, {1, 2}});
2003 
2005  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2006  armnn::IConnectableLayer* const padLayer = network->AddPadLayer(desc, layerName.c_str());
2007  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2008 
2009  inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
2010  padLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2011 
2012  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2013  padLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2014 
2015  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2016  BOOST_CHECK(deserializedNetwork);
2017 
2018  PadLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, desc);
2019  deserializedNetwork->Accept(verifier);
2020 }
2021 
2022 BOOST_AUTO_TEST_CASE(EnsurePadBackwardCompatibility)
2023 {
2024  // The PadDescriptor is being extended with a float PadValue (so a value other than 0
2025  // can be used to pad the tensor.
2026  //
2027  // This test contains a binary representation of a simple input->pad->output network
2028  // prior to this change to test that the descriptor has been updated in a backward
2029  // compatible way with respect to Deserialization of older binary dumps
2030  const std::vector<uint8_t> padModel =
2031  {
2032  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2033  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2034  0x54, 0x01, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2035  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD0, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2036  0x04, 0x00, 0x00, 0x00, 0x96, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
2037  0x00, 0x00, 0x72, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2038  0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
2039  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
2040  0x00, 0x00, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x16, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00,
2041  0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2042  0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00,
2043  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2044  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
2045  0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
2046  0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00,
2047  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
2048  0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
2049  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2050  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2051  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
2052  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00,
2053  0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00,
2054  0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2055  0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00,
2056  0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2057  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2058  0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2059  0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
2060  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
2061  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00
2062  };
2063 
2064  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(padModel.begin(), padModel.end()));
2065  BOOST_CHECK(deserializedNetwork);
2066 
2067  const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 1, 2, 3, 4 }, armnn::DataType::Float32);
2068  const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 1, 3, 5, 7 }, armnn::DataType::Float32);
2069 
2070  armnn::PadDescriptor descriptor({{ 0, 0 }, { 1, 0 }, { 1, 1 }, { 1, 2 }});
2071 
2072  PadLayerVerifier verifier("pad", { inputInfo }, { outputInfo }, descriptor);
2073  deserializedNetwork->Accept(verifier);
2074 }
2075 
2076 BOOST_AUTO_TEST_CASE(SerializePermute)
2077 {
2079 
2080  const std::string layerName("permute");
2081  const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2082  const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2083 
2084  armnn::PermuteDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2085 
2087  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2088  armnn::IConnectableLayer* const permuteLayer = network->AddPermuteLayer(descriptor, layerName.c_str());
2089  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2090 
2091  inputLayer->GetOutputSlot(0).Connect(permuteLayer->GetInputSlot(0));
2092  permuteLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2093 
2094  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2095  permuteLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2096 
2097  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2098  BOOST_CHECK(deserializedNetwork);
2099 
2100  PermuteLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2101  deserializedNetwork->Accept(verifier);
2102 }
2103 
2104 BOOST_AUTO_TEST_CASE(SerializePooling2d)
2105 {
2107 
2108  const std::string layerName("pooling2d");
2109  const armnn::TensorInfo inputInfo({1, 2, 2, 1}, armnn::DataType::Float32);
2110  const armnn::TensorInfo outputInfo({1, 1, 1, 1}, armnn::DataType::Float32);
2111 
2114  desc.m_PadTop = 0;
2115  desc.m_PadBottom = 0;
2116  desc.m_PadLeft = 0;
2117  desc.m_PadRight = 0;
2118  desc.m_PoolType = armnn::PoolingAlgorithm::Average;
2119  desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
2120  desc.m_PaddingMethod = armnn::PaddingMethod::Exclude;
2121  desc.m_PoolHeight = 2;
2122  desc.m_PoolWidth = 2;
2123  desc.m_StrideX = 2;
2124  desc.m_StrideY = 2;
2125 
2127  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2128  armnn::IConnectableLayer* const pooling2dLayer = network->AddPooling2dLayer(desc, layerName.c_str());
2129  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2130 
2131  inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0));
2132  pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2133 
2134  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2135  pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2136 
2137  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2138  BOOST_CHECK(deserializedNetwork);
2139 
2140  Pooling2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2141  deserializedNetwork->Accept(verifier);
2142 }
2143 
2144 BOOST_AUTO_TEST_CASE(SerializeQuantize)
2145 {
2147 
2148  const std::string layerName("quantize");
2149  const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
2150 
2152  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2153  armnn::IConnectableLayer* const quantizeLayer = network->AddQuantizeLayer(layerName.c_str());
2154  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2155 
2156  inputLayer->GetOutputSlot(0).Connect(quantizeLayer->GetInputSlot(0));
2157  quantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2158 
2159  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2160  quantizeLayer->GetOutputSlot(0).SetTensorInfo(info);
2161 
2162  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2163  BOOST_CHECK(deserializedNetwork);
2164 
2165  QuantizeLayerVerifier verifier(layerName, {info}, {info});
2166  deserializedNetwork->Accept(verifier);
2167 }
2168 
2169 BOOST_AUTO_TEST_CASE(SerializeReshape)
2170 {
2172 
2173  const std::string layerName("reshape");
2174  const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2175  const armnn::TensorInfo outputInfo({3, 3}, armnn::DataType::Float32);
2176 
2177  armnn::ReshapeDescriptor descriptor({3, 3});
2178 
2180  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2181  armnn::IConnectableLayer* const reshapeLayer = network->AddReshapeLayer(descriptor, layerName.c_str());
2182  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2183 
2184  inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0));
2185  reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2186 
2187  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2188  reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2189 
2190  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2191  BOOST_CHECK(deserializedNetwork);
2192 
2193  ReshapeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2194  deserializedNetwork->Accept(verifier);
2195 }
2196 
2197 BOOST_AUTO_TEST_CASE(SerializeResize)
2198 {
2200 
2201  const std::string layerName("resize");
2202  const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2203  const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2204 
2206  desc.m_TargetWidth = 4;
2207  desc.m_TargetHeight = 2;
2208  desc.m_Method = armnn::ResizeMethod::NearestNeighbor;
2209 
2211  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2212  armnn::IConnectableLayer* const resizeLayer = network->AddResizeLayer(desc, layerName.c_str());
2213  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2214 
2215  inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2216  resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2217 
2218  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2219  resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2220 
2221  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2222  BOOST_CHECK(deserializedNetwork);
2223 
2224  ResizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2225  deserializedNetwork->Accept(verifier);
2226 }
2227 
2228 class ResizeBilinearLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>
2229 {
2230 public:
2231  ResizeBilinearLayerVerifier(const std::string& layerName,
2232  const std::vector<armnn::TensorInfo>& inputInfos,
2233  const std::vector<armnn::TensorInfo>& outputInfos,
2234  const armnn::ResizeBilinearDescriptor& descriptor)
2235  : LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>(
2236  layerName, inputInfos, outputInfos, descriptor) {}
2237 
2238  void VisitResizeLayer(const armnn::IConnectableLayer* layer,
2239  const armnn::ResizeDescriptor& descriptor,
2240  const char* name) override
2241  {
2242  VerifyNameAndConnections(layer, name);
2243 
2245  BOOST_CHECK(descriptor.m_TargetWidth == m_Descriptor.m_TargetWidth);
2246  BOOST_CHECK(descriptor.m_TargetHeight == m_Descriptor.m_TargetHeight);
2247  BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
2248  }
2249 
2250  void VisitResizeBilinearLayer(const armnn::IConnectableLayer*,
2252  const char*) override
2253  {
2254  throw armnn::Exception("ResizeBilinearLayer should have translated to ResizeLayer");
2255  }
2256 };
2257 
2258 // NOTE: Until the deprecated AddResizeBilinearLayer disappears this test checks that
2259 // calling AddResizeBilinearLayer places a ResizeLayer into the serialized format
2260 // and that when this deserialises we have a ResizeLayer
2261 BOOST_AUTO_TEST_CASE(SerializeResizeBilinear)
2262 {
2263  const std::string layerName("resizeBilinear");
2264  const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2265  const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2266 
2268  desc.m_TargetWidth = 4u;
2269  desc.m_TargetHeight = 2u;
2270 
2272  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2274  armnn::IConnectableLayer* const resizeLayer = network->AddResizeBilinearLayer(desc, layerName.c_str());
2276  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2277 
2278  inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2279  resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2280 
2281  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2282  resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2283 
2284  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2285  BOOST_CHECK(deserializedNetwork);
2286 
2287  ResizeBilinearLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2288  deserializedNetwork->Accept(verifier);
2289 }
2290 
2291 BOOST_AUTO_TEST_CASE(EnsureResizeBilinearBackwardCompatibility)
2292 {
2293  // The hex data below is a flat buffer containing a simple network with an input,
2294  // a ResizeBilinearLayer (now deprecated) and an output
2295  //
2296  // This test verifies that we can still deserialize this old-style model by replacing
2297  // the ResizeBilinearLayer with an equivalent ResizeLayer
2298  const std::vector<uint8_t> resizeBilinearModel =
2299  {
2300  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2301  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2302  0x50, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2303  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD4, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2304  0x04, 0x00, 0x00, 0x00, 0xC2, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
2305  0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8A, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
2306  0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2307  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2308  0x38, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
2309  0x00, 0x1A, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
2310  0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x08, 0x00, 0x0C, 0x00,
2311  0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
2312  0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00,
2313  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
2314  0x20, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x42, 0x69, 0x6C, 0x69,
2315  0x6E, 0x65, 0x61, 0x72, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2316  0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
2317  0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2318  0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
2319  0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2320  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
2321  0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
2322  0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00,
2323  0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
2324  0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2325  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00,
2326  0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00,
2327  0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2328  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2329  0x00, 0x00, 0x05, 0x00, 0x00, 0x00
2330  };
2331 
2332  armnn::INetworkPtr deserializedNetwork =
2333  DeserializeNetwork(std::string(resizeBilinearModel.begin(), resizeBilinearModel.end()));
2334  BOOST_CHECK(deserializedNetwork);
2335 
2336  const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2337  const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2338 
2340  descriptor.m_TargetWidth = 4u;
2341  descriptor.m_TargetHeight = 2u;
2342 
2343  ResizeBilinearLayerVerifier verifier("resizeBilinear", { inputInfo }, { outputInfo }, descriptor);
2344  deserializedNetwork->Accept(verifier);
2345 }
2346 
2347 BOOST_AUTO_TEST_CASE(SerializeSlice)
2348 {
2350 
2351  const std::string layerName{"slice"};
2352 
2353  const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2354  const armnn::TensorInfo outputInfo = armnn::TensorInfo({2, 2, 2, 1}, armnn::DataType::Float32);
2355 
2356  armnn::SliceDescriptor descriptor({ 0, 0, 1, 0}, {2, 2, 2, 1});
2357 
2359 
2360  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2361  armnn::IConnectableLayer* const sliceLayer = network->AddSliceLayer(descriptor, layerName.c_str());
2362  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2363 
2364  inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
2365  sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2366 
2367  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2368  sliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2369 
2370  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2371  BOOST_CHECK(deserializedNetwork);
2372 
2373  SliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2374  deserializedNetwork->Accept(verifier);
2375 }
2376 
2377 BOOST_AUTO_TEST_CASE(SerializeSoftmax)
2378 {
2380 
2381  const std::string layerName("softmax");
2383 
2384  armnn::SoftmaxDescriptor descriptor;
2385  descriptor.m_Beta = 1.0f;
2386 
2388  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2389  armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, layerName.c_str());
2390  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2391 
2392  inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
2393  softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2394 
2395  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2396  softmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
2397 
2398  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2399  BOOST_CHECK(deserializedNetwork);
2400 
2401  SoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
2402  deserializedNetwork->Accept(verifier);
2403 }
2404 
2405 BOOST_AUTO_TEST_CASE(SerializeSpaceToBatchNd)
2406 {
2408 
2409  const std::string layerName("spaceToBatchNd");
2410  const armnn::TensorInfo inputInfo({2, 1, 2, 4}, armnn::DataType::Float32);
2411  const armnn::TensorInfo outputInfo({8, 1, 1, 3}, armnn::DataType::Float32);
2412 
2415  desc.m_BlockShape = {2, 2};
2416  desc.m_PadList = {{0, 0}, {2, 0}};
2417 
2419  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2420  armnn::IConnectableLayer* const spaceToBatchNdLayer = network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2421  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2422 
2423  inputLayer->GetOutputSlot(0).Connect(spaceToBatchNdLayer->GetInputSlot(0));
2424  spaceToBatchNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2425 
2426  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2427  spaceToBatchNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2428 
2429  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2430  BOOST_CHECK(deserializedNetwork);
2431 
2432  SpaceToBatchNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2433  deserializedNetwork->Accept(verifier);
2434 }
2435 
2436 BOOST_AUTO_TEST_CASE(SerializeSpaceToDepth)
2437 {
2439 
2440  const std::string layerName("spaceToDepth");
2441 
2442  const armnn::TensorInfo inputInfo ({ 1, 16, 8, 3 }, armnn::DataType::Float32);
2443  const armnn::TensorInfo outputInfo({ 1, 8, 4, 12 }, armnn::DataType::Float32);
2444 
2446  desc.m_BlockSize = 2;
2447  desc.m_DataLayout = armnn::DataLayout::NHWC;
2448 
2450  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2451  armnn::IConnectableLayer* const spaceToDepthLayer = network->AddSpaceToDepthLayer(desc, layerName.c_str());
2452  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2453 
2454  inputLayer->GetOutputSlot(0).Connect(spaceToDepthLayer->GetInputSlot(0));
2455  spaceToDepthLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2456 
2457  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2458  spaceToDepthLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2459 
2460  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2461  BOOST_CHECK(deserializedNetwork);
2462 
2463  SpaceToDepthLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2464  deserializedNetwork->Accept(verifier);
2465 }
2466 
2467 BOOST_AUTO_TEST_CASE(SerializeSplitter)
2468 {
2470 
2471  const unsigned int numViews = 3;
2472  const unsigned int numDimensions = 4;
2473  const unsigned int inputShape[] = {1, 18, 4, 4};
2474  const unsigned int outputShape[] = {1, 6, 4, 4};
2475 
2476  // This is modelled on how the caffe parser sets up a splitter layer to partition an input along dimension one.
2477  unsigned int splitterDimSizes[4] = {static_cast<unsigned int>(inputShape[0]),
2478  static_cast<unsigned int>(inputShape[1]),
2479  static_cast<unsigned int>(inputShape[2]),
2480  static_cast<unsigned int>(inputShape[3])};
2481  splitterDimSizes[1] /= numViews;
2482  armnn::ViewsDescriptor desc(numViews, numDimensions);
2483 
2484  for (unsigned int g = 0; g < numViews; ++g)
2485  {
2486  desc.SetViewOriginCoord(g, 1, splitterDimSizes[1] * g);
2487 
2488  for (unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
2489  {
2490  desc.SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
2491  }
2492  }
2493 
2494  const std::string layerName("splitter");
2495  const armnn::TensorInfo inputInfo(numDimensions, inputShape, armnn::DataType::Float32);
2496  const armnn::TensorInfo outputInfo(numDimensions, outputShape, armnn::DataType::Float32);
2497 
2499  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2500  armnn::IConnectableLayer* const splitterLayer = network->AddSplitterLayer(desc, layerName.c_str());
2501  armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2502  armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2503  armnn::IConnectableLayer* const outputLayer2 = network->AddOutputLayer(2);
2504 
2505  inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
2506  splitterLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2507  splitterLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2508  splitterLayer->GetOutputSlot(2).Connect(outputLayer2->GetInputSlot(0));
2509 
2510  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2511  splitterLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2512  splitterLayer->GetOutputSlot(1).SetTensorInfo(outputInfo);
2513  splitterLayer->GetOutputSlot(2).SetTensorInfo(outputInfo);
2514 
2515  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2516  BOOST_CHECK(deserializedNetwork);
2517 
2518  SplitterLayerVerifier verifier(layerName, {inputInfo}, {outputInfo, outputInfo, outputInfo}, desc);
2519  deserializedNetwork->Accept(verifier);
2520 }
2521 
2522 BOOST_AUTO_TEST_CASE(SerializeStack)
2523 {
2525 
2526  const std::string layerName("stack");
2527 
2528  armnn::TensorInfo inputTensorInfo ({4, 3, 5}, armnn::DataType::Float32);
2529  armnn::TensorInfo outputTensorInfo({4, 3, 2, 5}, armnn::DataType::Float32);
2530 
2531  armnn::StackDescriptor descriptor(2, 2, {4, 3, 5});
2532 
2534  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
2535  armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
2536  armnn::IConnectableLayer* const stackLayer = network->AddStackLayer(descriptor, layerName.c_str());
2537  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2538 
2539  inputLayer1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
2540  inputLayer2->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
2541  stackLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2542 
2543  inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2544  inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2545  stackLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2546 
2547  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2548  BOOST_CHECK(deserializedNetwork);
2549 
2550  StackLayerVerifier verifier(layerName, {inputTensorInfo, inputTensorInfo}, {outputTensorInfo}, descriptor);
2551  deserializedNetwork->Accept(verifier);
2552 }
2553 
2554 BOOST_AUTO_TEST_CASE(SerializeStandIn)
2555 {
2557 
2558  const std::string layerName("standIn");
2559 
2560  armnn::TensorInfo tensorInfo({ 1u }, armnn::DataType::Float32);
2561  armnn::StandInDescriptor descriptor(2u, 2u);
2562 
2564  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2565  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2566  armnn::IConnectableLayer* const standInLayer = network->AddStandInLayer(descriptor, layerName.c_str());
2567  armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2568  armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2569 
2570  inputLayer0->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(0));
2571  inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2572 
2573  inputLayer1->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(1));
2574  inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2575 
2576  standInLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2577  standInLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2578 
2579  standInLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2580  standInLayer->GetOutputSlot(1).SetTensorInfo(tensorInfo);
2581 
2582  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2583  BOOST_CHECK(deserializedNetwork);
2584 
2585  StandInLayerVerifier verifier(layerName, { tensorInfo, tensorInfo }, { tensorInfo, tensorInfo }, descriptor);
2586  deserializedNetwork->Accept(verifier);
2587 }
2588 
2589 BOOST_AUTO_TEST_CASE(SerializeStridedSlice)
2590 {
2592 
2593  const std::string layerName("stridedSlice");
2594  const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2595  const armnn::TensorInfo outputInfo = armnn::TensorInfo({3, 1}, armnn::DataType::Float32);
2596 
2597  armnn::StridedSliceDescriptor desc({0, 0, 1, 0}, {1, 1, 1, 1}, {1, 1, 1, 1});
2598  desc.m_EndMask = (1 << 4) - 1;
2599  desc.m_ShrinkAxisMask = (1 << 1) | (1 << 2);
2600  desc.m_DataLayout = armnn::DataLayout::NCHW;
2601 
2603  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2604  armnn::IConnectableLayer* const stridedSliceLayer = network->AddStridedSliceLayer(desc, layerName.c_str());
2605  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2606 
2607  inputLayer->GetOutputSlot(0).Connect(stridedSliceLayer->GetInputSlot(0));
2608  stridedSliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2609 
2610  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2611  stridedSliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2612 
2613  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2614  BOOST_CHECK(deserializedNetwork);
2615 
2616  StridedSliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2617  deserializedNetwork->Accept(verifier);
2618 }
2619 
2620 BOOST_AUTO_TEST_CASE(SerializeSubtraction)
2621 {
2623 
2624  const std::string layerName("subtraction");
2626 
2628  armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2629  armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2630  armnn::IConnectableLayer* const subtractionLayer = network->AddSubtractionLayer(layerName.c_str());
2631  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2632 
2633  inputLayer0->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(0));
2634  inputLayer1->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(1));
2635  subtractionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2636 
2637  inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2638  inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2639  subtractionLayer->GetOutputSlot(0).SetTensorInfo(info);
2640 
2641  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2642  BOOST_CHECK(deserializedNetwork);
2643 
2644  SubtractionLayerVerifier verifier(layerName, {info, info}, {info});
2645  deserializedNetwork->Accept(verifier);
2646 }
2647 
2648 BOOST_AUTO_TEST_CASE(SerializeSwitch)
2649 {
2650  class SwitchLayerVerifier : public LayerVerifierBase
2651  {
2652  public:
2653  SwitchLayerVerifier(const std::string& layerName,
2654  const std::vector<armnn::TensorInfo>& inputInfos,
2655  const std::vector<armnn::TensorInfo>& outputInfos)
2656  : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2657 
2658  void VisitSwitchLayer(const armnn::IConnectableLayer* layer, const char* name) override
2659  {
2660  VerifyNameAndConnections(layer, name);
2661  }
2662 
2663  void VisitConstantLayer(const armnn::IConnectableLayer*,
2664  const armnn::ConstTensor&,
2665  const char*) override {}
2666  };
2667 
2668  const std::string layerName("switch");
2670 
2671  std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2672  armnn::ConstTensor constTensor(info, constantData);
2673 
2675  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2676  armnn::IConnectableLayer* const constantLayer = network->AddConstantLayer(constTensor, "constant");
2677  armnn::IConnectableLayer* const switchLayer = network->AddSwitchLayer(layerName.c_str());
2678  armnn::IConnectableLayer* const trueOutputLayer = network->AddOutputLayer(0);
2679  armnn::IConnectableLayer* const falseOutputLayer = network->AddOutputLayer(1);
2680 
2681  inputLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(0));
2682  constantLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(1));
2683  switchLayer->GetOutputSlot(0).Connect(trueOutputLayer->GetInputSlot(0));
2684  switchLayer->GetOutputSlot(1).Connect(falseOutputLayer->GetInputSlot(0));
2685 
2686  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2687  constantLayer->GetOutputSlot(0).SetTensorInfo(info);
2688  switchLayer->GetOutputSlot(0).SetTensorInfo(info);
2689  switchLayer->GetOutputSlot(1).SetTensorInfo(info);
2690 
2691  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2692  BOOST_CHECK(deserializedNetwork);
2693 
2694  SwitchLayerVerifier verifier(layerName, {info, info}, {info, info});
2695  deserializedNetwork->Accept(verifier);
2696 }
2697 
2698 BOOST_AUTO_TEST_CASE(SerializeTranspose)
2699 {
2701 
2702  const std::string layerName("transpose");
2703  const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2704  const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2705 
2706  armnn::TransposeDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2707 
2709  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2710  armnn::IConnectableLayer* const transposeLayer = network->AddTransposeLayer(descriptor, layerName.c_str());
2711  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2712 
2713  inputLayer->GetOutputSlot(0).Connect(transposeLayer->GetInputSlot(0));
2714  transposeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2715 
2716  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2717  transposeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2718 
2719  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2720  BOOST_CHECK(deserializedNetwork);
2721 
2722  TransposeLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2723  deserializedNetwork->Accept(verifier);
2724 }
2725 
2726 BOOST_AUTO_TEST_CASE(SerializeTransposeConvolution2d)
2727 {
2728  using Descriptor = armnn::TransposeConvolution2dDescriptor;
2729  class TransposeConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
2730  {
2731  public:
2732  TransposeConvolution2dLayerVerifier(const std::string& layerName,
2733  const std::vector<armnn::TensorInfo>& inputInfos,
2734  const std::vector<armnn::TensorInfo>& outputInfos,
2735  const Descriptor& descriptor,
2736  const armnn::ConstTensor& weights,
2738  : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
2739  , m_Weights(weights)
2740  , m_Biases(biases)
2741  {}
2742 
2743  void VisitTransposeConvolution2dLayer(const armnn::IConnectableLayer* layer,
2744  const Descriptor& descriptor,
2745  const armnn::ConstTensor& weights,
2747  const char* name) override
2748  {
2749  VerifyNameAndConnections(layer, name);
2750  VerifyDescriptor(descriptor);
2751 
2752  // check weights
2753  CompareConstTensor(weights, m_Weights);
2754 
2755  // check biases
2756  BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
2757  BOOST_CHECK(biases.has_value() == m_Biases.has_value());
2758 
2759  if (biases.has_value() && m_Biases.has_value())
2760  {
2761  CompareConstTensor(biases.value(), m_Biases.value());
2762  }
2763  }
2764 
2765  private:
2766  armnn::ConstTensor m_Weights;
2768  };
2769 
2770  const std::string layerName("transposeConvolution2d");
2771  const armnn::TensorInfo inputInfo ({ 1, 7, 7, 1 }, armnn::DataType::Float32);
2772  const armnn::TensorInfo outputInfo({ 1, 9, 9, 1 }, armnn::DataType::Float32);
2773 
2774  const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
2775  const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
2776 
2777  std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
2778  armnn::ConstTensor weights(weightsInfo, weightsData);
2779 
2780  std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
2781  armnn::ConstTensor biases(biasesInfo, biasesData);
2782 
2784  descriptor.m_PadLeft = 1;
2785  descriptor.m_PadRight = 1;
2786  descriptor.m_PadTop = 1;
2787  descriptor.m_PadBottom = 1;
2788  descriptor.m_StrideX = 1;
2789  descriptor.m_StrideY = 1;
2790  descriptor.m_BiasEnabled = true;
2792 
2794  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2795  armnn::IConnectableLayer* const convLayer =
2796  network->AddTransposeConvolution2dLayer(descriptor,
2797  weights,
2799  layerName.c_str());
2800  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2801 
2802  inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
2803  convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2804 
2805  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2806  convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2807 
2808  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2809  BOOST_CHECK(deserializedNetwork);
2810 
2811  TransposeConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
2812  deserializedNetwork->Accept(verifier);
2813 }
2814 
2815 BOOST_AUTO_TEST_CASE(SerializeDeserializeNonLinearNetwork)
2816 {
2817  class ConstantLayerVerifier : public LayerVerifierBase
2818  {
2819  public:
2820  ConstantLayerVerifier(const std::string& layerName,
2821  const std::vector<armnn::TensorInfo>& inputInfos,
2822  const std::vector<armnn::TensorInfo>& outputInfos,
2823  const armnn::ConstTensor& layerInput)
2824  : LayerVerifierBase(layerName, inputInfos, outputInfos)
2825  , m_LayerInput(layerInput) {}
2826 
2827  void VisitConstantLayer(const armnn::IConnectableLayer* layer,
2828  const armnn::ConstTensor& input,
2829  const char* name) override
2830  {
2831  VerifyNameAndConnections(layer, name);
2832  CompareConstTensor(input, m_LayerInput);
2833  }
2834 
2835  void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
2836 
2837  private:
2838  armnn::ConstTensor m_LayerInput;
2839  };
2840 
2841  const std::string layerName("constant");
2843 
2844  std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2845  armnn::ConstTensor constTensor(info, constantData);
2846 
2848  armnn::IConnectableLayer* input = network->AddInputLayer(0);
2849  armnn::IConnectableLayer* add = network->AddAdditionLayer();
2850  armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
2851  armnn::IConnectableLayer* output = network->AddOutputLayer(0);
2852 
2853  input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
2854  constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
2855  add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2856 
2857  input->GetOutputSlot(0).SetTensorInfo(info);
2858  constant->GetOutputSlot(0).SetTensorInfo(info);
2859  add->GetOutputSlot(0).SetTensorInfo(info);
2860 
2861  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2862  BOOST_CHECK(deserializedNetwork);
2863 
2864  ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
2865  deserializedNetwork->Accept(verifier);
2866 }
2867 
2868 class VerifyLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>
2869 {
2870 public:
2871  VerifyLstmLayer(const std::string& layerName,
2872  const std::vector<armnn::TensorInfo>& inputInfos,
2873  const std::vector<armnn::TensorInfo>& outputInfos,
2874  const armnn::LstmDescriptor& descriptor,
2875  const armnn::LstmInputParams& inputParams)
2876  : LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
2877  , m_InputParams(inputParams) {}
2878 
2879  void VisitLstmLayer(const armnn::IConnectableLayer* layer,
2880  const armnn::LstmDescriptor& descriptor,
2881  const armnn::LstmInputParams& params,
2882  const char* name)
2883  {
2884  VerifyNameAndConnections(layer, name);
2885  VerifyDescriptor(descriptor);
2886  VerifyInputParameters(params);
2887  }
2888 
2889 protected:
2890  void VerifyInputParameters(const armnn::LstmInputParams& params)
2891  {
2892  VerifyConstTensors(
2893  "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
2894  VerifyConstTensors(
2895  "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
2896  VerifyConstTensors(
2897  "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
2898  VerifyConstTensors(
2899  "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
2900  VerifyConstTensors(
2901  "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
2902  VerifyConstTensors(
2903  "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
2904  VerifyConstTensors(
2905  "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
2906  VerifyConstTensors(
2907  "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
2908  VerifyConstTensors(
2909  "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
2910  VerifyConstTensors(
2911  "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
2912  VerifyConstTensors(
2913  "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
2914  VerifyConstTensors(
2915  "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
2916  VerifyConstTensors(
2917  "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
2918  VerifyConstTensors(
2919  "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
2920  VerifyConstTensors(
2921  "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
2922  VerifyConstTensors(
2923  "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
2924  VerifyConstTensors(
2925  "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
2926  VerifyConstTensors(
2927  "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
2928  VerifyConstTensors(
2929  "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
2930  VerifyConstTensors(
2931  "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
2932  VerifyConstTensors(
2933  "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
2934  }
2935 
2936 private:
2937  armnn::LstmInputParams m_InputParams;
2938 };
2939 
2940 BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmCifgPeepholeNoProjection)
2941 {
2942  armnn::LstmDescriptor descriptor;
2943  descriptor.m_ActivationFunc = 4;
2944  descriptor.m_ClippingThresProj = 0.0f;
2945  descriptor.m_ClippingThresCell = 0.0f;
2946  descriptor.m_CifgEnabled = true; // if this is true then we DON'T need to set the OptCifgParams
2947  descriptor.m_ProjectionEnabled = false;
2948  descriptor.m_PeepholeEnabled = true;
2949 
2950  const uint32_t batchSize = 1;
2951  const uint32_t inputSize = 2;
2952  const uint32_t numUnits = 4;
2953  const uint32_t outputSize = numUnits;
2954 
2955  armnn::TensorInfo inputWeightsInfo1({numUnits, inputSize}, armnn::DataType::Float32);
2956  std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
2957  armnn::ConstTensor inputToForgetWeights(inputWeightsInfo1, inputToForgetWeightsData);
2958 
2959  std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
2960  armnn::ConstTensor inputToCellWeights(inputWeightsInfo1, inputToCellWeightsData);
2961 
2962  std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
2963  armnn::ConstTensor inputToOutputWeights(inputWeightsInfo1, inputToOutputWeightsData);
2964 
2965  armnn::TensorInfo inputWeightsInfo2({numUnits, outputSize}, armnn::DataType::Float32);
2966  std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
2967  armnn::ConstTensor recurrentToForgetWeights(inputWeightsInfo2, recurrentToForgetWeightsData);
2968 
2969  std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
2970  armnn::ConstTensor recurrentToCellWeights(inputWeightsInfo2, recurrentToCellWeightsData);
2971 
2972  std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
2973  armnn::ConstTensor recurrentToOutputWeights(inputWeightsInfo2, recurrentToOutputWeightsData);
2974 
2975  armnn::TensorInfo inputWeightsInfo3({numUnits}, armnn::DataType::Float32);
2976  std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
2977  armnn::ConstTensor cellToForgetWeights(inputWeightsInfo3, cellToForgetWeightsData);
2978 
2979  std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
2980  armnn::ConstTensor cellToOutputWeights(inputWeightsInfo3, cellToOutputWeightsData);
2981 
2982  std::vector<float> forgetGateBiasData(numUnits, 1.0f);
2983  armnn::ConstTensor forgetGateBias(inputWeightsInfo3, forgetGateBiasData);
2984 
2985  std::vector<float> cellBiasData(numUnits, 0.0f);
2986  armnn::ConstTensor cellBias(inputWeightsInfo3, cellBiasData);
2987 
2988  std::vector<float> outputGateBiasData(numUnits, 0.0f);
2989  armnn::ConstTensor outputGateBias(inputWeightsInfo3, outputGateBiasData);
2990 
2991  armnn::LstmInputParams params;
2992  params.m_InputToForgetWeights = &inputToForgetWeights;
2993  params.m_InputToCellWeights = &inputToCellWeights;
2994  params.m_InputToOutputWeights = &inputToOutputWeights;
2995  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
2996  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
2997  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
2998  params.m_ForgetGateBias = &forgetGateBias;
2999  params.m_CellBias = &cellBias;
3000  params.m_OutputGateBias = &outputGateBias;
3001  params.m_CellToForgetWeights = &cellToForgetWeights;
3002  params.m_CellToOutputWeights = &cellToOutputWeights;
3003 
3005  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3006  armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3007  armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3008  const std::string layerName("lstm");
3009  armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3010  armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3011  armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3012  armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3013  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3014 
3015  // connect up
3016  armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3017  armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3018  armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3019  armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 3 }, armnn::DataType::Float32);
3020 
3021  inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3022  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3023 
3024  outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3025  outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3026 
3027  cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3028  cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3029 
3030  lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3031  lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3032 
3033  lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3034  lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3035 
3036  lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3037  lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3038 
3039  lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3040  lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3041 
3042  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3043  BOOST_CHECK(deserializedNetwork);
3044 
3045  VerifyLstmLayer checker(
3046  layerName,
3047  {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3048  {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3049  descriptor,
3050  params);
3051  deserializedNetwork->Accept(checker);
3052 }
3053 
3054 BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeAndProjection)
3055 {
3056  armnn::LstmDescriptor descriptor;
3057  descriptor.m_ActivationFunc = 4;
3058  descriptor.m_ClippingThresProj = 0.0f;
3059  descriptor.m_ClippingThresCell = 0.0f;
3060  descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3061  descriptor.m_ProjectionEnabled = true;
3062  descriptor.m_PeepholeEnabled = true;
3063 
3064  const uint32_t batchSize = 2;
3065  const uint32_t inputSize = 5;
3066  const uint32_t numUnits = 20;
3067  const uint32_t outputSize = 16;
3068 
3069  armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3070  std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3071  armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3072 
3073  std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3074  armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3075 
3076  std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3077  armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3078 
3079  std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3080  armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3081 
3082  armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3083  std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3084  armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3085 
3086  std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3087  armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3088 
3089  std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3090  armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3091 
3092  std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3093  armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3094 
3095  armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3096  std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3097  armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3098 
3099  std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3100  armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3101 
3102  std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3103  armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3104 
3105  std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3106  armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3107 
3108  std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3109  armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3110 
3111  std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3112  armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3113 
3114  std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3115  armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3116 
3117  armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3118  std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3119  armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3120 
3121  armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3122  std::vector<float> projectionBiasData(outputSize, 0.f);
3123  armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3124 
3125  armnn::LstmInputParams params;
3126  params.m_InputToForgetWeights = &inputToForgetWeights;
3127  params.m_InputToCellWeights = &inputToCellWeights;
3128  params.m_InputToOutputWeights = &inputToOutputWeights;
3129  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3130  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3131  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3132  params.m_ForgetGateBias = &forgetGateBias;
3133  params.m_CellBias = &cellBias;
3134  params.m_OutputGateBias = &outputGateBias;
3135 
3136  // additional params because: descriptor.m_CifgEnabled = false
3137  params.m_InputToInputWeights = &inputToInputWeights;
3138  params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3139  params.m_CellToInputWeights = &cellToInputWeights;
3140  params.m_InputGateBias = &inputGateBias;
3141 
3142  // additional params because: descriptor.m_ProjectionEnabled = true
3143  params.m_ProjectionWeights = &projectionWeights;
3144  params.m_ProjectionBias = &projectionBias;
3145 
3146  // additional params because: descriptor.m_PeepholeEnabled = true
3147  params.m_CellToForgetWeights = &cellToForgetWeights;
3148  params.m_CellToOutputWeights = &cellToOutputWeights;
3149 
3151  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3152  armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3153  armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3154  const std::string layerName("lstm");
3155  armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3156  armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3157  armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3158  armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3159  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3160 
3161  // connect up
3162  armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3163  armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3164  armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3165  armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3166 
3167  inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3168  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3169 
3170  outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3171  outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3172 
3173  cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3174  cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3175 
3176  lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3177  lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3178 
3179  lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3180  lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3181 
3182  lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3183  lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3184 
3185  lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3186  lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3187 
3188  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3189  BOOST_CHECK(deserializedNetwork);
3190 
3191  VerifyLstmLayer checker(
3192  layerName,
3193  {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3194  {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3195  descriptor,
3196  params);
3197  deserializedNetwork->Accept(checker);
3198 }
3199 
3200 BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeWithProjectionWithLayerNorm)
3201 {
3202  armnn::LstmDescriptor descriptor;
3203  descriptor.m_ActivationFunc = 4;
3204  descriptor.m_ClippingThresProj = 0.0f;
3205  descriptor.m_ClippingThresCell = 0.0f;
3206  descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3207  descriptor.m_ProjectionEnabled = true;
3208  descriptor.m_PeepholeEnabled = true;
3209  descriptor.m_LayerNormEnabled = true;
3210 
3211  const uint32_t batchSize = 2;
3212  const uint32_t inputSize = 5;
3213  const uint32_t numUnits = 20;
3214  const uint32_t outputSize = 16;
3215 
3216  armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3217  std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3218  armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3219 
3220  std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3221  armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3222 
3223  std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3224  armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3225 
3226  std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3227  armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3228 
3229  armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3230  std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3231  armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3232 
3233  std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3234  armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3235 
3236  std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3237  armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3238 
3239  std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3240  armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3241 
3242  armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3243  std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3244  armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3245 
3246  std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3247  armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3248 
3249  std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3250  armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3251 
3252  std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3253  armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3254 
3255  std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3256  armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3257 
3258  std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3259  armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3260 
3261  std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3262  armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3263 
3264  armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3265  std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3266  armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3267 
3268  armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3269  std::vector<float> projectionBiasData(outputSize, 0.f);
3270  armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3271 
3272  std::vector<float> inputLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3273  armnn::ConstTensor inputLayerNormWeights(tensorInfo20, forgetGateBiasData);
3274 
3275  std::vector<float> forgetLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3276  armnn::ConstTensor forgetLayerNormWeights(tensorInfo20, forgetGateBiasData);
3277 
3278  std::vector<float> cellLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3279  armnn::ConstTensor cellLayerNormWeights(tensorInfo20, forgetGateBiasData);
3280 
3281  std::vector<float> outLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3282  armnn::ConstTensor outLayerNormWeights(tensorInfo20, forgetGateBiasData);
3283 
3284  armnn::LstmInputParams params;
3285  params.m_InputToForgetWeights = &inputToForgetWeights;
3286  params.m_InputToCellWeights = &inputToCellWeights;
3287  params.m_InputToOutputWeights = &inputToOutputWeights;
3288  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3289  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3290  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3291  params.m_ForgetGateBias = &forgetGateBias;
3292  params.m_CellBias = &cellBias;
3293  params.m_OutputGateBias = &outputGateBias;
3294 
3295  // additional params because: descriptor.m_CifgEnabled = false
3296  params.m_InputToInputWeights = &inputToInputWeights;
3297  params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3298  params.m_CellToInputWeights = &cellToInputWeights;
3299  params.m_InputGateBias = &inputGateBias;
3300 
3301  // additional params because: descriptor.m_ProjectionEnabled = true
3302  params.m_ProjectionWeights = &projectionWeights;
3303  params.m_ProjectionBias = &projectionBias;
3304 
3305  // additional params because: descriptor.m_PeepholeEnabled = true
3306  params.m_CellToForgetWeights = &cellToForgetWeights;
3307  params.m_CellToOutputWeights = &cellToOutputWeights;
3308 
3309  // additional params because: despriptor.m_LayerNormEnabled = true
3310  params.m_InputLayerNormWeights = &inputLayerNormWeights;
3311  params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3312  params.m_CellLayerNormWeights = &cellLayerNormWeights;
3313  params.m_OutputLayerNormWeights = &outLayerNormWeights;
3314 
3316  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3317  armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3318  armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3319  const std::string layerName("lstm");
3320  armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3321  armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3322  armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3323  armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3324  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3325 
3326  // connect up
3327  armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3328  armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3329  armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3330  armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3331 
3332  inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3333  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3334 
3335  outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3336  outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3337 
3338  cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3339  cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3340 
3341  lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3342  lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3343 
3344  lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3345  lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3346 
3347  lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3348  lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3349 
3350  lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3351  lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3352 
3353  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3354  BOOST_CHECK(deserializedNetwork);
3355 
3356  VerifyLstmLayer checker(
3357  layerName,
3358  {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3359  {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3360  descriptor,
3361  params);
3362  deserializedNetwork->Accept(checker);
3363 }
3364 
3365 BOOST_AUTO_TEST_CASE(EnsureLstmLayersBackwardCompatibility)
3366 {
3367  // The hex data below is a flat buffer containing a lstm layer with no Cifg, with peephole and projection
3368  // enabled. That data was obtained before additional layer normalization parameters where added to the
3369  // lstm serializer. That way it can be tested if a lstm model with the old parameter configuration can
3370  // still be loaded
3371  const std::vector<uint8_t> lstmNoCifgWithPeepholeAndProjectionModel =
3372  {
3373  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
3374  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
3375  0xDC, 0x29, 0x00, 0x00, 0x38, 0x29, 0x00, 0x00, 0xB4, 0x28, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x3C, 0x01,
3376  0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
3377  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
3378  0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0xD6, 0xFF, 0xFF,
3379  0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x06, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x88, 0xD7,
3380  0xFF, 0xFF, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF6, 0xD6, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
3381  0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
3382  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3383  0xE8, 0xD7, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xFF, 0xFF, 0x00, 0x00,
3384  0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x5E, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xE0, 0xD7, 0xFF, 0xFF,
3385  0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4E, 0xD7, 0xFF, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00,
3386  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3387  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD8,
3388  0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
3389  0x04, 0x00, 0x00, 0x00, 0xB6, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x38, 0xD8, 0xFF, 0xFF, 0x08, 0x00,
3390  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA6, 0xD7, 0xFF, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3391  0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3392  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xD8, 0xFF, 0xFF,
3393  0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00,
3394  0x00, 0x00, 0x0E, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x16, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3395  0xFA, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00,
3396  0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3397  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
3398  0x00, 0x00, 0x6C, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
3399  0x12, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE0, 0x25, 0x00, 0x00, 0xD0, 0x25,
3400  0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x48, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00,
3401  0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2C, 0x00, 0x30, 0x00,
3402  0x34, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x40, 0x00, 0x44, 0x00, 0x26, 0x00, 0x00, 0x00, 0xC4, 0x23, 0x00, 0x00,
3403  0xF8, 0x21, 0x00, 0x00, 0x2C, 0x20, 0x00, 0x00, 0xF0, 0x1A, 0x00, 0x00, 0xB4, 0x15, 0x00, 0x00, 0x78, 0x10,
3404  0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x68, 0x0F, 0x00, 0x00, 0xE0, 0x0E, 0x00, 0x00, 0x14, 0x0D, 0x00, 0x00,
3405  0xD8, 0x07, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0xC8, 0x06, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x14, 0x01,
3406  0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3407  0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00,
3408  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3409  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3410  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3411  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3412  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3413  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x72, 0xD8,
3414  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0xD9, 0xFF, 0xFF,
3415  0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3416  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3417  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3418  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3419  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xD8,
3420  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3421  0x14, 0x00, 0x00, 0x00, 0xF6, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x54, 0x00, 0x00, 0x00, 0x04, 0x00,
3422  0x00, 0x00, 0x06, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3423  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3424  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3425  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3426  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xD9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3427  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6A, 0xD9, 0xFF, 0xFF, 0x00, 0x00,
3428  0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7A, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3429  0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3430  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3431  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3432  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3433  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3434  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3435  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3436  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3437  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3438  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3439  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3440  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3441  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3442  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3443  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3444  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3445  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3446  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3447  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3448  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3449  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3450  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3451  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3452  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3453  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3454  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3455  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3456  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3457  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3458  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3459  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3460  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3461  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3462  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3463  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3464  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3465  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3466  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3467  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3468  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3469  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3470  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3471  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3472  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3473  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3474  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3475  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3476  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3477  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3478  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3479  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3480  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3481  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3482  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3483  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3484  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3485  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3486  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3487  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3488  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3489  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3490  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3491  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3492  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3493  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3494  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3495  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3496  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3497  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3498  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3499  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3500  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xDE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3501  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xA2, 0xDE,
3502  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB2, 0xDF, 0xFF, 0xFF,
3503  0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3504  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3505  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3506  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3507  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xDF,
3508  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3509  0x14, 0x00, 0x00, 0x00, 0x26, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00,
3510  0x00, 0x00, 0x36, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3511  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3512  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3513  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3514  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3515  0x00, 0x00, 0x00, 0x00, 0x92, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3516  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAA, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3517  0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xBA, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3518  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3519  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3520  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3521  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3522  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3523  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3524  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3525  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3526  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3527  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3528  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3529  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3530  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3531  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3532  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3533  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3534  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3535  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3536  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3537  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3538  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3539  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3540  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3541  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3542  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3543  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3549  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3550  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3551  0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00,
3556  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3557  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3558  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3563  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3564  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3565  0x00, 0x00, 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, 0xC6, 0xE4, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3590  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xE2, 0xE4, 0xFF, 0xFF,
3591  0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xE5, 0xFF, 0xFF, 0x04, 0x00,
3592  0x00, 0x00, 0x64, 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, 0x8E, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3615  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
3616  0x00, 0x00, 0xAA, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3617  0xBA, 0xE7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 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, 0x16, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3623  0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2E, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00,
3624  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3E, 0xE8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 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, 0x9A, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3630  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xB2, 0xE7, 0xFF, 0xFF,
3631  0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC2, 0xE8, 0xFF, 0xFF, 0x04, 0x00,
3632  0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3633  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3634  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3635  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3636  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE8, 0xFF, 0xFF,
3637  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00,
3638  0x00, 0x00, 0x36, 0xE8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3639  0x46, 0xE9, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 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, 0x00, 0x00,
3644  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3645  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3646  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3652  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3653  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x52, 0xED, 0xFF, 0xFF,
3711  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00,
3712  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6E, 0xED, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00,
3713  0x04, 0x00, 0x00, 0x00, 0x7E, 0xEE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00,
3714  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3715  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3716  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3717  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3718  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3719  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3720  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3721  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3722  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3723  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3724  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3725  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3726  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3727  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3728  0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3751  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3752  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3753  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3759  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3760  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3766  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3767  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3768  0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00,
3773  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3774  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3775  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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  0x8A, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3786  0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xA6, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3787  0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB6, 0xF3, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3788  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3789  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3790  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3791  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3792  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3793  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3794  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3795  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3796  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3797  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3798  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3799  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3800  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3801  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3802  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3803  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3804  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3805  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3806  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3807  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3808  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3809  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3810  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3811  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3812  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3813  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3814  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3815  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3816  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3817  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3818  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3819  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3820  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3821  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3822  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3823  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3824  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3825  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3826  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3827  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3828  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3829  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3830  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3831  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3832  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3833  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3834  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3835  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3836  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3837  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3838  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3839  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3840  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3841  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3842  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3843  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3844  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3845  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3846  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3847  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3848  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3849  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xC2, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3860  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xDE, 0xF7, 0xFF, 0xFF,
3861  0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xF8, 0xFF, 0xFF, 0x04, 0x00,
3862  0x00, 0x00, 0x64, 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, 0x8A, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3885  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
3886  0x00, 0x00, 0xA6, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3887  0xB6, 0xFA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 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, 0x52, 0xFB,
3910  0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
3911  0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6E, 0xFB, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01,
3912  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFC, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
3913  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3914  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3915  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3916  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3917  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3918  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3919  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3920  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3921  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3922  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3923  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x1A, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3936  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x00,
3937  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
3938  0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x2E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3939  0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6C, 0x73,
3940  0x74, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00,
3941  0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x30, 0x00,
3942  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3943  0xA6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3944  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
3945  0x04, 0x00, 0x00, 0x00, 0xCE, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3946  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x64, 0xFF, 0xFF, 0xFF,
3947  0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3948  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3949  0xB4, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x1A, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3950  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
3951  0xF0, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
3952  0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
3953  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3954  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
3955  0x7E, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00,
3956  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x76, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
3957  0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
3958  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3959  0x68, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3960  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3961  0x08, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00,
3962  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
3963  0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00,
3964  0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00,
3965  0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
3966  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3967  0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
3968  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6E, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3969  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00,
3970  0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
3971  0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00,
3972  0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
3973  0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
3974  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3975  0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
3976  0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00,
3977  0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3978  0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00
3979  };
3980 
3981  armnn::INetworkPtr deserializedNetwork =
3982  DeserializeNetwork(std::string(lstmNoCifgWithPeepholeAndProjectionModel.begin(),
3983  lstmNoCifgWithPeepholeAndProjectionModel.end()));
3984 
3985  BOOST_CHECK(deserializedNetwork);
3986 
3987  // generating the same model parameters which where used to serialize the model (Layer norm is not specified)
3988  armnn::LstmDescriptor descriptor;
3989  descriptor.m_ActivationFunc = 4;
3990  descriptor.m_ClippingThresProj = 0.0f;
3991  descriptor.m_ClippingThresCell = 0.0f;
3992  descriptor.m_CifgEnabled = false;
3993  descriptor.m_ProjectionEnabled = true;
3994  descriptor.m_PeepholeEnabled = true;
3995 
3996  const uint32_t batchSize = 2u;
3997  const uint32_t inputSize = 5u;
3998  const uint32_t numUnits = 20u;
3999  const uint32_t outputSize = 16u;
4000 
4001  armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
4002  std::vector<float> inputToInputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4003  armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
4004 
4005  std::vector<float> inputToForgetWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4006  armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
4007 
4008  std::vector<float> inputToCellWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4009  armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
4010 
4011  std::vector<float> inputToOutputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4012  armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
4013 
4014  armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
4015  std::vector<float> inputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4016  armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
4017 
4018  std::vector<float> forgetGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4019  armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
4020 
4021  std::vector<float> cellBiasData(tensorInfo20.GetNumElements(), 0.0f);
4022  armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
4023 
4024  std::vector<float> outputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4025  armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
4026 
4027  armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
4028  std::vector<float> recurrentToInputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4029  armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
4030 
4031  std::vector<float> recurrentToForgetWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4032  armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
4033 
4034  std::vector<float> recurrentToCellWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4035  armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
4036 
4037  std::vector<float> recurrentToOutputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4038  armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
4039 
4040  std::vector<float> cellToInputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4041  armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
4042 
4043  std::vector<float> cellToForgetWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4044  armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
4045 
4046  std::vector<float> cellToOutputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4047  armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
4048 
4049  armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
4050  std::vector<float> projectionWeightsData(tensorInfo16x20.GetNumElements(), 0.0f);
4051  armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
4052 
4053  armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
4054  std::vector<float> projectionBiasData(outputSize, 0.0f);
4055  armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
4056 
4057  armnn::LstmInputParams params;
4058  params.m_InputToForgetWeights = &inputToForgetWeights;
4059  params.m_InputToCellWeights = &inputToCellWeights;
4060  params.m_InputToOutputWeights = &inputToOutputWeights;
4061  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4062  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4063  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4064  params.m_ForgetGateBias = &forgetGateBias;
4065  params.m_CellBias = &cellBias;
4066  params.m_OutputGateBias = &outputGateBias;
4067 
4068  // additional params because: descriptor.m_CifgEnabled = false
4069  params.m_InputToInputWeights = &inputToInputWeights;
4070  params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4071  params.m_CellToInputWeights = &cellToInputWeights;
4072  params.m_InputGateBias = &inputGateBias;
4073 
4074  // additional params because: descriptor.m_ProjectionEnabled = true
4075  params.m_ProjectionWeights = &projectionWeights;
4076  params.m_ProjectionBias = &projectionBias;
4077 
4078  // additional params because: descriptor.m_PeepholeEnabled = true
4079  params.m_CellToForgetWeights = &cellToForgetWeights;
4080  params.m_CellToOutputWeights = &cellToOutputWeights;
4081 
4082  const std::string layerName("lstm");
4083  armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
4084  armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
4085  armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
4086  armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
4087 
4088  VerifyLstmLayer checker(
4089  layerName,
4090  {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
4091  {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4092  descriptor,
4093  params);
4094  deserializedNetwork->Accept(checker);
4095 }
4096 class VerifyQuantizedLstmLayer : public LayerVerifierBase
4097 {
4098 
4099 public:
4100  VerifyQuantizedLstmLayer(const std::string& layerName,
4101  const std::vector<armnn::TensorInfo>& inputInfos,
4102  const std::vector<armnn::TensorInfo>& outputInfos,
4103  const armnn::QuantizedLstmInputParams& inputParams)
4104  : LayerVerifierBase(layerName, inputInfos, outputInfos), m_InputParams(inputParams) {}
4105 
4106  void VisitQuantizedLstmLayer(const armnn::IConnectableLayer* layer,
4107  const armnn::QuantizedLstmInputParams& params,
4108  const char* name)
4109  {
4110  VerifyNameAndConnections(layer, name);
4111  VerifyInputParameters(params);
4112  }
4113 
4114 protected:
4115  void VerifyInputParameters(const armnn::QuantizedLstmInputParams& params)
4116  {
4117  VerifyConstTensors("m_InputToInputWeights",
4118  m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4119  VerifyConstTensors("m_InputToForgetWeights",
4120  m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4121  VerifyConstTensors("m_InputToCellWeights",
4122  m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4123  VerifyConstTensors("m_InputToOutputWeights",
4124  m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4125  VerifyConstTensors("m_RecurrentToInputWeights",
4126  m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4127  VerifyConstTensors("m_RecurrentToForgetWeights",
4128  m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4129  VerifyConstTensors("m_RecurrentToCellWeights",
4130  m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4131  VerifyConstTensors("m_RecurrentToOutputWeights",
4132  m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4133  VerifyConstTensors("m_InputGateBias",
4134  m_InputParams.m_InputGateBias, params.m_InputGateBias);
4135  VerifyConstTensors("m_ForgetGateBias",
4136  m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4137  VerifyConstTensors("m_CellBias",
4138  m_InputParams.m_CellBias, params.m_CellBias);
4139  VerifyConstTensors("m_OutputGateBias",
4140  m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4141  }
4142 
4143 private:
4144  armnn::QuantizedLstmInputParams m_InputParams;
4145 };
4146 
4147 BOOST_AUTO_TEST_CASE(SerializeDeserializeQuantizedLstm)
4148 {
4149  const uint32_t batchSize = 1;
4150  const uint32_t inputSize = 2;
4151  const uint32_t numUnits = 4;
4152  const uint32_t outputSize = numUnits;
4153 
4154  // Scale/Offset for input/output, cellState In/Out, weights, bias
4155  float inputOutputScale = 0.0078125f;
4156  int32_t inputOutputOffset = 128;
4157 
4158  float cellStateScale = 0.00048828125f;
4159  int32_t cellStateOffset = 0;
4160 
4161  float weightsScale = 0.00408021f;
4162  int32_t weightsOffset = 100;
4163 
4164  float biasScale = 3.1876640625e-05f;
4165  int32_t biasOffset = 0;
4166 
4167  // The shape of weight data is {outputSize, inputSize} = {4, 2}
4168  armnn::TensorShape inputToInputWeightsShape = {4, 2};
4169  std::vector<uint8_t> inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4170  armnn::TensorInfo inputToInputWeightsInfo(inputToInputWeightsShape,
4172  weightsScale,
4173  weightsOffset);
4174  armnn::ConstTensor inputToInputWeights(inputToInputWeightsInfo, inputToInputWeightsData);
4175 
4176  armnn::TensorShape inputToForgetWeightsShape = {4, 2};
4177  std::vector<uint8_t> inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4178  armnn::TensorInfo inputToForgetWeightsInfo(inputToForgetWeightsShape,
4180  weightsScale,
4181  weightsOffset);
4182  armnn::ConstTensor inputToForgetWeights(inputToForgetWeightsInfo, inputToForgetWeightsData);
4183 
4184  armnn::TensorShape inputToCellWeightsShape = {4, 2};
4185  std::vector<uint8_t> inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4186  armnn::TensorInfo inputToCellWeightsInfo(inputToCellWeightsShape,
4188  weightsScale,
4189  weightsOffset);
4190  armnn::ConstTensor inputToCellWeights(inputToCellWeightsInfo, inputToCellWeightsData);
4191 
4192  armnn::TensorShape inputToOutputWeightsShape = {4, 2};
4193  std::vector<uint8_t> inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4194  armnn::TensorInfo inputToOutputWeightsInfo(inputToOutputWeightsShape,
4196  weightsScale,
4197  weightsOffset);
4198  armnn::ConstTensor inputToOutputWeights(inputToOutputWeightsInfo, inputToOutputWeightsData);
4199 
4200  // The shape of recurrent weight data is {outputSize, outputSize} = {4, 4}
4201  armnn::TensorShape recurrentToInputWeightsShape = {4, 4};
4202  std::vector<uint8_t> recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4203  armnn::TensorInfo recurrentToInputWeightsInfo(recurrentToInputWeightsShape,
4205  weightsScale,
4206  weightsOffset);
4207  armnn::ConstTensor recurrentToInputWeights(recurrentToInputWeightsInfo, recurrentToInputWeightsData);
4208 
4209  armnn::TensorShape recurrentToForgetWeightsShape = {4, 4};
4210  std::vector<uint8_t> recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4211  armnn::TensorInfo recurrentToForgetWeightsInfo(recurrentToForgetWeightsShape,
4213  weightsScale,
4214  weightsOffset);
4215  armnn::ConstTensor recurrentToForgetWeights(recurrentToForgetWeightsInfo, recurrentToForgetWeightsData);
4216 
4217  armnn::TensorShape recurrentToCellWeightsShape = {4, 4};
4218  std::vector<uint8_t> recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4219  armnn::TensorInfo recurrentToCellWeightsInfo(recurrentToCellWeightsShape,
4221  weightsScale,
4222  weightsOffset);
4223  armnn::ConstTensor recurrentToCellWeights(recurrentToCellWeightsInfo, recurrentToCellWeightsData);
4224 
4225  armnn::TensorShape recurrentToOutputWeightsShape = {4, 4};
4226  std::vector<uint8_t> recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4227  armnn::TensorInfo recurrentToOutputWeightsInfo(recurrentToOutputWeightsShape,
4229  weightsScale,
4230  weightsOffset);
4231  armnn::ConstTensor recurrentToOutputWeights(recurrentToOutputWeightsInfo, recurrentToOutputWeightsData);
4232 
4233  // The shape of bias data is {outputSize} = {4}
4234  armnn::TensorShape inputGateBiasShape = {4};
4235  std::vector<int32_t> inputGateBiasData = {1, 2, 3, 4};
4236  armnn::TensorInfo inputGateBiasInfo(inputGateBiasShape,
4238  biasScale,
4239  biasOffset);
4240  armnn::ConstTensor inputGateBias(inputGateBiasInfo, inputGateBiasData);
4241 
4242  armnn::TensorShape forgetGateBiasShape = {4};
4243  std::vector<int32_t> forgetGateBiasData = {1, 2, 3, 4};
4244  armnn::TensorInfo forgetGateBiasInfo(forgetGateBiasShape,
4246  biasScale,
4247  biasOffset);
4248  armnn::ConstTensor forgetGateBias(forgetGateBiasInfo, forgetGateBiasData);
4249 
4250  armnn::TensorShape cellBiasShape = {4};
4251  std::vector<int32_t> cellBiasData = {1, 2, 3, 4};
4252  armnn::TensorInfo cellBiasInfo(cellBiasShape,
4254  biasScale,
4255  biasOffset);
4256  armnn::ConstTensor cellBias(cellBiasInfo, cellBiasData);
4257 
4258  armnn::TensorShape outputGateBiasShape = {4};
4259  std::vector<int32_t> outputGateBiasData = {1, 2, 3, 4};
4260  armnn::TensorInfo outputGateBiasInfo(outputGateBiasShape,
4262  biasScale,
4263  biasOffset);
4264  armnn::ConstTensor outputGateBias(outputGateBiasInfo, outputGateBiasData);
4265 
4267  params.m_InputToInputWeights = &inputToInputWeights;
4268  params.m_InputToForgetWeights = &inputToForgetWeights;
4269  params.m_InputToCellWeights = &inputToCellWeights;
4270  params.m_InputToOutputWeights = &inputToOutputWeights;
4271  params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4272  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4273  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4274  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4275  params.m_InputGateBias = &inputGateBias;
4276  params.m_ForgetGateBias = &forgetGateBias;
4277  params.m_CellBias = &cellBias;
4278  params.m_OutputGateBias = &outputGateBias;
4279 
4281  armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
4282  armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
4283  armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
4284  const std::string layerName("QuantizedLstm");
4285  armnn::IConnectableLayer* const quantizedLstmLayer = network->AddQuantizedLstmLayer(params, layerName.c_str());
4286  armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(0);
4287  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(1);
4288 
4289  // Connect up
4290  armnn::TensorInfo inputTensorInfo({ batchSize, inputSize },
4292  inputOutputScale,
4293  inputOutputOffset);
4294  armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits },
4296  cellStateScale,
4297  cellStateOffset);
4298  armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize },
4300  inputOutputScale,
4301  inputOutputOffset);
4302 
4303  inputLayer->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(0));
4304  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
4305 
4306  cellStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(1));
4307  cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4308 
4309  outputStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(2));
4310  outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
4311 
4312  quantizedLstmLayer->GetOutputSlot(0).Connect(cellStateOut->GetInputSlot(0));
4313  quantizedLstmLayer->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4314 
4315  quantizedLstmLayer->GetOutputSlot(1).Connect(outputLayer->GetInputSlot(0));
4316  quantizedLstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
4317 
4318  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4319  BOOST_CHECK(deserializedNetwork);
4320 
4321  VerifyQuantizedLstmLayer checker(layerName,
4322  {inputTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4323  {cellStateTensorInfo, outputStateTensorInfo},
4324  params);
4325 
4326  deserializedNetwork->Accept(checker);
4327 }
4328 
4329 class VerifyQLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>
4330 {
4331 public:
4332  VerifyQLstmLayer(const std::string& layerName,
4333  const std::vector<armnn::TensorInfo>& inputInfos,
4334  const std::vector<armnn::TensorInfo>& outputInfos,
4335  const armnn::QLstmDescriptor& descriptor,
4336  const armnn::LstmInputParams& inputParams)
4337  : LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
4338  , m_InputParams(inputParams) {}
4339 
4340  void VisitQLstmLayer(const armnn::IConnectableLayer* layer,
4341  const armnn::QLstmDescriptor& descriptor,
4342  const armnn::LstmInputParams& params,
4343  const char* name)
4344  {
4345  VerifyNameAndConnections(layer, name);
4346  VerifyDescriptor(descriptor);
4347  VerifyInputParameters(params);
4348  }
4349 
4350 protected:
4351  void VerifyInputParameters(const armnn::LstmInputParams& params)
4352  {
4353  VerifyConstTensors(
4354  "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4355  VerifyConstTensors(
4356  "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4357  VerifyConstTensors(
4358  "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4359  VerifyConstTensors(
4360  "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4361  VerifyConstTensors(
4362  "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4363  VerifyConstTensors(
4364  "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4365  VerifyConstTensors(
4366  "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4367  VerifyConstTensors(
4368  "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4369  VerifyConstTensors(
4370  "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
4371  VerifyConstTensors(
4372  "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
4373  VerifyConstTensors(
4374  "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
4375  VerifyConstTensors(
4376  "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
4377  VerifyConstTensors(
4378  "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4379  VerifyConstTensors(
4380  "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
4381  VerifyConstTensors(
4382  "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4383  VerifyConstTensors(
4384  "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
4385  VerifyConstTensors(
4386  "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
4387  VerifyConstTensors(
4388  "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
4389  VerifyConstTensors(
4390  "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
4391  VerifyConstTensors(
4392  "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
4393  VerifyConstTensors(
4394  "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
4395  }
4396 
4397 private:
4398  armnn::LstmInputParams m_InputParams;
4399 };
4400 
4401 BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmBasic)
4402 {
4403  armnn::QLstmDescriptor descriptor;
4404 
4405  descriptor.m_CifgEnabled = true;
4406  descriptor.m_ProjectionEnabled = false;
4407  descriptor.m_PeepholeEnabled = false;
4408  descriptor.m_LayerNormEnabled = false;
4409 
4410  descriptor.m_CellClip = 0.0f;
4411  descriptor.m_ProjectionClip = 0.0f;
4412 
4413  descriptor.m_InputIntermediateScale = 0.00001f;
4414  descriptor.m_ForgetIntermediateScale = 0.00001f;
4415  descriptor.m_CellIntermediateScale = 0.00001f;
4416  descriptor.m_OutputIntermediateScale = 0.00001f;
4417 
4418  descriptor.m_HiddenStateScale = 0.07f;
4419  descriptor.m_HiddenStateZeroPoint = 0;
4420 
4421  const unsigned int numBatches = 2;
4422  const unsigned int inputSize = 5;
4423  const unsigned int outputSize = 4;
4424  const unsigned int numUnits = 4;
4425 
4426  // Scale/Offset quantization info
4427  float inputScale = 0.0078f;
4428  int32_t inputOffset = 0;
4429 
4430  float outputScale = 0.0078f;
4431  int32_t outputOffset = 0;
4432 
4433  float cellStateScale = 3.5002e-05f;
4434  int32_t cellStateOffset = 0;
4435 
4436  float weightsScale = 0.007f;
4437  int32_t weightsOffset = 0;
4438 
4439  float biasScale = 3.5002e-05f / 1024;
4440  int32_t biasOffset = 0;
4441 
4442  // Weights and bias tensor and quantization info
4443  armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4445  weightsScale,
4446  weightsOffset);
4447 
4448  armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4450  weightsScale,
4451  weightsOffset);
4452 
4453  armnn::TensorInfo biasInfo({numUnits}, armnn::DataType::Signed32, biasScale, biasOffset);
4454 
4455  std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4456  std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4457  std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4458 
4459  armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4460  armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4461  armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4462 
4463  std::vector<int8_t> recurrentToForgetWeightsData =
4464  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4465  std::vector<int8_t> recurrentToCellWeightsData =
4466  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4467  std::vector<int8_t> recurrentToOutputWeightsData =
4468  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4469 
4470  armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4471  armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4472  armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4473 
4474  std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4475  std::vector<int32_t> cellBiasData(numUnits, 0);
4476  std::vector<int32_t> outputGateBiasData(numUnits, 0);
4477 
4478  armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4479  armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4480  armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4481 
4482  // Set up params
4483  armnn::LstmInputParams params;
4484  params.m_InputToForgetWeights = &inputToForgetWeights;
4485  params.m_InputToCellWeights = &inputToCellWeights;
4486  params.m_InputToOutputWeights = &inputToOutputWeights;
4487 
4488  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4489  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4490  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4491 
4492  params.m_ForgetGateBias = &forgetGateBias;
4493  params.m_CellBias = &cellBias;
4494  params.m_OutputGateBias = &outputGateBias;
4495 
4496  // Create network
4498  const std::string layerName("qLstm");
4499 
4500  armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4501  armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4502  armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4503 
4504  armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4505 
4506  armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4507  armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4508  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4509 
4510  // Input/Output tensor info
4511  armnn::TensorInfo inputInfo({numBatches , inputSize},
4513  inputScale,
4514  inputOffset);
4515 
4516  armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4518  cellStateScale,
4519  cellStateOffset);
4520 
4521  armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4523  outputScale,
4524  outputOffset);
4525 
4526  // Connect input/output slots
4527  input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4528  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4529 
4530  outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4531  outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4532 
4533  cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4534  cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4535 
4536  qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4537  qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4538 
4539  qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4540  qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4541 
4542  qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4543  qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4544 
4545  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4546  BOOST_CHECK(deserializedNetwork);
4547 
4548  VerifyQLstmLayer checker(layerName,
4549  {inputInfo, cellStateInfo, outputStateInfo},
4550  {outputStateInfo, cellStateInfo, outputStateInfo},
4551  descriptor,
4552  params);
4553 
4554  deserializedNetwork->Accept(checker);
4555 }
4556 
4557 BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmCifgLayerNorm)
4558 {
4559  armnn::QLstmDescriptor descriptor;
4560 
4561  // CIFG params are used when CIFG is disabled
4562  descriptor.m_CifgEnabled = true;
4563  descriptor.m_ProjectionEnabled = false;
4564  descriptor.m_PeepholeEnabled = false;
4565  descriptor.m_LayerNormEnabled = true;
4566 
4567  descriptor.m_CellClip = 0.0f;
4568  descriptor.m_ProjectionClip = 0.0f;
4569 
4570  descriptor.m_InputIntermediateScale = 0.00001f;
4571  descriptor.m_ForgetIntermediateScale = 0.00001f;
4572  descriptor.m_CellIntermediateScale = 0.00001f;
4573  descriptor.m_OutputIntermediateScale = 0.00001f;
4574 
4575  descriptor.m_HiddenStateScale = 0.07f;
4576  descriptor.m_HiddenStateZeroPoint = 0;
4577 
4578  const unsigned int numBatches = 2;
4579  const unsigned int inputSize = 5;
4580  const unsigned int outputSize = 4;
4581  const unsigned int numUnits = 4;
4582 
4583  // Scale/Offset quantization info
4584  float inputScale = 0.0078f;
4585  int32_t inputOffset = 0;
4586 
4587  float outputScale = 0.0078f;
4588  int32_t outputOffset = 0;
4589 
4590  float cellStateScale = 3.5002e-05f;
4591  int32_t cellStateOffset = 0;
4592 
4593  float weightsScale = 0.007f;
4594  int32_t weightsOffset = 0;
4595 
4596  float layerNormScale = 3.5002e-05f;
4597  int32_t layerNormOffset = 0;
4598 
4599  float biasScale = layerNormScale / 1024;
4600  int32_t biasOffset = 0;
4601 
4602  // Weights and bias tensor and quantization info
4603  armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4605  weightsScale,
4606  weightsOffset);
4607 
4608  armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4610  weightsScale,
4611  weightsOffset);
4612 
4613  armnn::TensorInfo biasInfo({numUnits},
4615  biasScale,
4616  biasOffset);
4617 
4618  armnn::TensorInfo layerNormWeightsInfo({numUnits},
4620  layerNormScale,
4621  layerNormOffset);
4622 
4623  // Mandatory params
4624  std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4625  std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4626  std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4627 
4628  armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4629  armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4630  armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4631 
4632  std::vector<int8_t> recurrentToForgetWeightsData =
4633  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4634  std::vector<int8_t> recurrentToCellWeightsData =
4635  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4636  std::vector<int8_t> recurrentToOutputWeightsData =
4637  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4638 
4639  armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4640  armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4641  armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4642 
4643  std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4644  std::vector<int32_t> cellBiasData(numUnits, 0);
4645  std::vector<int32_t> outputGateBiasData(numUnits, 0);
4646 
4647  armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4648  armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4649  armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4650 
4651  // Layer Norm
4652  std::vector<int16_t> forgetLayerNormWeightsData =
4653  GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4654  std::vector<int16_t> cellLayerNormWeightsData =
4655  GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4656  std::vector<int16_t> outputLayerNormWeightsData =
4657  GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4658 
4659  armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
4660  armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
4661  armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
4662 
4663  // Set up params
4664  armnn::LstmInputParams params;
4665 
4666  // Mandatory params
4667  params.m_InputToForgetWeights = &inputToForgetWeights;
4668  params.m_InputToCellWeights = &inputToCellWeights;
4669  params.m_InputToOutputWeights = &inputToOutputWeights;
4670 
4671  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4672  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4673  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4674 
4675  params.m_ForgetGateBias = &forgetGateBias;
4676  params.m_CellBias = &cellBias;
4677  params.m_OutputGateBias = &outputGateBias;
4678 
4679  // Layer Norm
4680  params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
4681  params.m_CellLayerNormWeights = &cellLayerNormWeights;
4682  params.m_OutputLayerNormWeights = &outputLayerNormWeights;
4683 
4684  // Create network
4686  const std::string layerName("qLstm");
4687 
4688  armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4689  armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4690  armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4691 
4692  armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4693 
4694  armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4695  armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4696  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4697 
4698  // Input/Output tensor info
4699  armnn::TensorInfo inputInfo({numBatches , inputSize},
4701  inputScale,
4702  inputOffset);
4703 
4704  armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4706  cellStateScale,
4707  cellStateOffset);
4708 
4709  armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4711  outputScale,
4712  outputOffset);
4713 
4714  // Connect input/output slots
4715  input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4716  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4717 
4718  outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4719  outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4720 
4721  cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4722  cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4723 
4724  qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4725  qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4726 
4727  qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4728  qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4729 
4730  qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4731  qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4732 
4733  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4734  BOOST_CHECK(deserializedNetwork);
4735 
4736  VerifyQLstmLayer checker(layerName,
4737  {inputInfo, cellStateInfo, outputStateInfo},
4738  {outputStateInfo, cellStateInfo, outputStateInfo},
4739  descriptor,
4740  params);
4741 
4742  deserializedNetwork->Accept(checker);
4743 }
4744 
4745 BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmAdvanced)
4746 {
4747  armnn::QLstmDescriptor descriptor;
4748 
4749  descriptor.m_CifgEnabled = false;
4750  descriptor.m_ProjectionEnabled = true;
4751  descriptor.m_PeepholeEnabled = true;
4752  descriptor.m_LayerNormEnabled = true;
4753 
4754  descriptor.m_CellClip = 0.1f;
4755  descriptor.m_ProjectionClip = 0.1f;
4756 
4757  descriptor.m_InputIntermediateScale = 0.00001f;
4758  descriptor.m_ForgetIntermediateScale = 0.00001f;
4759  descriptor.m_CellIntermediateScale = 0.00001f;
4760  descriptor.m_OutputIntermediateScale = 0.00001f;
4761 
4762  descriptor.m_HiddenStateScale = 0.07f;
4763  descriptor.m_HiddenStateZeroPoint = 0;
4764 
4765  const unsigned int numBatches = 2;
4766  const unsigned int inputSize = 5;
4767  const unsigned int outputSize = 4;
4768  const unsigned int numUnits = 4;
4769 
4770  // Scale/Offset quantization info
4771  float inputScale = 0.0078f;
4772  int32_t inputOffset = 0;
4773 
4774  float outputScale = 0.0078f;
4775  int32_t outputOffset = 0;
4776 
4777  float cellStateScale = 3.5002e-05f;
4778  int32_t cellStateOffset = 0;
4779 
4780  float weightsScale = 0.007f;
4781  int32_t weightsOffset = 0;
4782 
4783  float layerNormScale = 3.5002e-05f;
4784  int32_t layerNormOffset = 0;
4785 
4786  float biasScale = layerNormScale / 1024;
4787  int32_t biasOffset = 0;
4788 
4789  // Weights and bias tensor and quantization info
4790  armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4792  weightsScale,
4793  weightsOffset);
4794 
4795  armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4797  weightsScale,
4798  weightsOffset);
4799 
4800  armnn::TensorInfo biasInfo({numUnits},
4802  biasScale,
4803  biasOffset);
4804 
4805  armnn::TensorInfo peepholeWeightsInfo({numUnits},
4807  weightsScale,
4808  weightsOffset);
4809 
4810  armnn::TensorInfo layerNormWeightsInfo({numUnits},
4812  layerNormScale,
4813  layerNormOffset);
4814 
4815  armnn::TensorInfo projectionWeightsInfo({outputSize, numUnits},
4817  weightsScale,
4818  weightsOffset);
4819 
4820  // Mandatory params
4821  std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4822  std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4823  std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4824 
4825  armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4826  armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4827  armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4828 
4829  std::vector<int8_t> recurrentToForgetWeightsData =
4830  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4831  std::vector<int8_t> recurrentToCellWeightsData =
4832  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4833  std::vector<int8_t> recurrentToOutputWeightsData =
4834  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4835 
4836  armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4837  armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4838  armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4839 
4840  std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4841  std::vector<int32_t> cellBiasData(numUnits, 0);
4842  std::vector<int32_t> outputGateBiasData(numUnits, 0);
4843 
4844  armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4845  armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4846  armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4847 
4848  // CIFG
4849  std::vector<int8_t> inputToInputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4850  std::vector<int8_t> recurrentToInputWeightsData =
4851  GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4852  std::vector<int32_t> inputGateBiasData(numUnits, 1);
4853 
4854  armnn::ConstTensor inputToInputWeights(inputWeightsInfo, inputToInputWeightsData);
4855  armnn::ConstTensor recurrentToInputWeights(recurrentWeightsInfo, recurrentToInputWeightsData);
4856  armnn::ConstTensor inputGateBias(biasInfo, inputGateBiasData);
4857 
4858  // Peephole
4859  std::vector<int16_t> cellToInputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4860  std::vector<int16_t> cellToForgetWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4861  std::vector<int16_t> cellToOutputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4862 
4863  armnn::ConstTensor cellToInputWeights(peepholeWeightsInfo, cellToInputWeightsData);
4864  armnn::ConstTensor cellToForgetWeights(peepholeWeightsInfo, cellToForgetWeightsData);
4865  armnn::ConstTensor cellToOutputWeights(peepholeWeightsInfo, cellToOutputWeightsData);
4866 
4867  // Projection
4868  std::vector<int8_t> projectionWeightsData = GenerateRandomData<int8_t>(projectionWeightsInfo.GetNumElements());
4869  std::vector<int32_t> projectionBiasData(outputSize, 1);
4870 
4871  armnn::ConstTensor projectionWeights(projectionWeightsInfo, projectionWeightsData);
4872  armnn::ConstTensor projectionBias(biasInfo, projectionBiasData);
4873 
4874  // Layer Norm
4875  std::vector<int16_t> inputLayerNormWeightsData =
4876  GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4877  std::vector<int16_t> forgetLayerNormWeightsData =
4878  GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4879  std::vector<int16_t> cellLayerNormWeightsData =
4880  GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4881  std::vector<int16_t> outputLayerNormWeightsData =
4882  GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4883 
4884  armnn::ConstTensor inputLayerNormWeights(layerNormWeightsInfo, inputLayerNormWeightsData);
4885  armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
4886  armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
4887  armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
4888 
4889  // Set up params
4890  armnn::LstmInputParams params;
4891 
4892  // Mandatory params
4893  params.m_InputToForgetWeights = &inputToForgetWeights;
4894  params.m_InputToCellWeights = &inputToCellWeights;
4895  params.m_InputToOutputWeights = &inputToOutputWeights;
4896 
4897  params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4898  params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4899  params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4900 
4901  params.m_ForgetGateBias = &forgetGateBias;
4902  params.m_CellBias = &cellBias;
4903  params.m_OutputGateBias = &outputGateBias;
4904 
4905  // CIFG
4906  params.m_InputToInputWeights = &inputToInputWeights;
4907  params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4908  params.m_InputGateBias = &inputGateBias;
4909 
4910  // Peephole
4911  params.m_CellToInputWeights = &cellToInputWeights;
4912  params.m_CellToForgetWeights = &cellToForgetWeights;
4913  params.m_CellToOutputWeights = &cellToOutputWeights;
4914 
4915  // Projection
4916  params.m_ProjectionWeights = &projectionWeights;
4917  params.m_ProjectionBias = &projectionBias;
4918 
4919  // Layer Norm
4920  params.m_InputLayerNormWeights = &inputLayerNormWeights;
4921  params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
4922  params.m_CellLayerNormWeights = &cellLayerNormWeights;
4923  params.m_OutputLayerNormWeights = &outputLayerNormWeights;
4924 
4925  // Create network
4927  const std::string layerName("qLstm");
4928 
4929  armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4930  armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4931  armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4932 
4933  armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4934 
4935  armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4936  armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4937  armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4938 
4939  // Input/Output tensor info
4940  armnn::TensorInfo inputInfo({numBatches , inputSize},
4942  inputScale,
4943  inputOffset);
4944 
4945  armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4947  cellStateScale,
4948  cellStateOffset);
4949 
4950  armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4952  outputScale,
4953  outputOffset);
4954 
4955  // Connect input/output slots
4956  input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4957  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4958 
4959  outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4960  outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4961 
4962  cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4963  cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4964 
4965  qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4966  qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4967 
4968  qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4969  qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4970 
4971  qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4972  qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4973 
4974  armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4975  BOOST_CHECK(deserializedNetwork);
4976 
4977  VerifyQLstmLayer checker(layerName,
4978  {inputInfo, cellStateInfo, outputStateInfo},
4979  {outputStateInfo, cellStateInfo, outputStateInfo},
4980  descriptor,
4981  params);
4982 
4983  deserializedNetwork->Accept(checker);
4984 }
4985 
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
virtual unsigned int GetNumOutputSlots() const =0
Returns the number of connectable output slots.
bool m_ProjectionEnabled
Enable/disable the projection layer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
const ConstTensor * m_ProjectionWeights
Definition: LstmParams.hpp:55
float Dequantize(QuantizedType value, float scale, int32_t offset)
Dequantize an 8-bit data type into a floating point data type.
Definition: TypesUtils.cpp:47
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:61
float m_ScaleW
Center size encoding scale weight.
const ConstTensor * m_CellBias
Definition: LstmParams.hpp:53
bool m_BiasEnabled
Enable/disable bias.
virtual unsigned int GetNumInputSlots() const =0
Returns the number of connectable input slots.
void Slice(const TensorInfo &inputInfo, const SliceDescriptor &descriptor, const void *inputData, void *outputData, unsigned int dataTypeSize)
Definition: Slice.cpp:16
A TransposeConvolution2dDescriptor for the TransposeConvolution2dLayer.
const TensorShape & GetShape() const
Definition: Tensor.hpp:88
const ConstTensor * m_RecurrentToOutputWeights
uint32_t m_PadBottom
Padding bottom value in the height dimension.
float m_ClippingThresProj
Clipping threshold value for the projection.
A ReshapeDescriptor for the ReshapeLayer.
void ArgMinMax(Decoder< float > &in, int32_t *out, const TensorInfo &inputTensorInfo, const TensorInfo &outputTensorInfo, ArgMinMaxFunction function, int axis)
Definition: ArgMinMax.cpp:15
const ConstTensor * m_CellToOutputWeights
Definition: LstmParams.hpp:50
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
const ConstTensor * m_RecurrentToForgetWeights
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
A ComparisonDescriptor for the ComparisonLayer.
Definition: Descriptors.hpp:70
float m_ScaleX
Center size encoding scale x.
uint32_t m_TargetWidth
Target width value.
bool m_TransposeWeightMatrix
Enable/disable transpose weight matrix.
bool m_PeepholeEnabled
Enable/disable peephole.
A Convolution2dDescriptor for the Convolution2dLayer.
uint32_t m_PadLeft
Padding left value in the width dimension.
float m_HiddenStateScale
Hidden State quantization scale.
bool m_BiasEnabled
Enable/disable bias.
const ConstTensor * m_CellToInputWeights
Definition: LstmParams.hpp:48
const TensorShape & GetShape() const
Definition: Tensor.hpp:169
float m_OutputIntermediateScale
Output intermediate quantization scale.
ResizeMethod m_Method
The Interpolation method to use (Bilinear, NearestNeighbor).
float m_Gamma
Gamma, the scale scalar value applied for the normalized tensor. Defaults to 1.0. ...
float m_Beta
Exponentiation value.
The padding fields don&#39;t count and are ignored.
float m_Eps
Value to add to the variance. Used to avoid dividing by zero.
const ConstTensor * m_InputGateBias
Definition: LstmParams.hpp:51
ArgMinMaxFunction m_Function
Specify if the function is to find Min or Max.
Definition: Descriptors.hpp:64
uint32_t m_DetectionsPerClass
Detections per classes, used in Regular NMS.
armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32)
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
Main network class which provides the interface for building up a neural network. ...
Definition: INetwork.hpp:105
unsigned int GetNumElements() const
Definition: Tensor.hpp:175
const ConstTensor * m_RecurrentToCellWeights
Definition: LstmParams.hpp:46
void Serialize(const armnn::INetwork &inNetwork) override
Serializes the network to ArmNN SerializedGraph.
void Transpose(const armnn::TensorShape &dstShape, const armnn::PermutationVector &mappings, const void *src, void *dst, size_t dataTypeSize)
Definition: Transpose.cpp:120
void DepthToSpace(const TensorInfo &inputInfo, const DepthToSpaceDescriptor &descriptor, const void *inputData, void *outputData, unsigned int dataTypeSize)
uint32_t m_PadRight
Padding right value in the width dimension.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
MemoryType GetMemoryArea() const
Definition: Tensor.hpp:177
const ConstTensor * m_ForgetLayerNormWeights
Definition: LstmParams.hpp:58
const ConstTensor * m_CellToForgetWeights
Definition: LstmParams.hpp:49
Copyright (c) 2020 ARM Limited.
uint32_t m_PadBottom
Padding bottom value in the height dimension.
uint32_t m_DilationY
Dilation along y axis.
int32_t m_EndMask
End mask value.
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
uint32_t m_DilationY
Dilation factor value for height dimension.
#define DECLARE_LAYER_VERIFIER_CLASS(name)
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:171
const ConstTensor * m_OutputGateBias
Definition: LstmParams.hpp:54
void Stack(const StackQueueDescriptor &data, std::vector< std::unique_ptr< Decoder< float >>> &inputs, Encoder< float > &output)
Definition: Stack.cpp:12
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
constexpr const char * GetDataTypeName(DataType dataType)
Definition: TypesUtils.hpp:168
A ResizeDescriptor for the ResizeLayer.
BOOST_AUTO_TEST_CASE(SerializeAddition)
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
uint32_t m_MaxClassesPerDetection
Maximum numbers of classes per detection, used in Fast NMS.
std::vector< unsigned int > m_Axis
Values for the dimensions to reduce.
A StackDescriptor for the StackLayer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
void Pad(const TensorInfo &inputInfo, const TensorInfo &outputInfo, std::vector< std::pair< unsigned int, unsigned int >> m_padList, const T *inputData, T *outData, const float padValue)
Definition: Pad.cpp:22
uint32_t m_PadTop
Padding top value in the height dimension.
uint32_t m_MaxDetections
Maximum numbers of detections.
A PadDescriptor for the PadLayer.
void Permute(const armnn::TensorShape &dstShape, const armnn::PermutationVector &mappings, const void *src, void *dst, size_t dataTypeSize)
Definition: Permute.cpp:121
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
const ConstTensor * m_InputLayerNormWeights
Definition: LstmParams.hpp:57
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
bool m_LayerNormEnabled
Enable/disable layer normalization.
DataType
Definition: Types.hpp:32
float m_NmsIouThreshold
Intersection over union threshold.
const ConstTensor * m_RecurrentToOutputWeights
Definition: LstmParams.hpp:47
An LstmDescriptor for the LstmLayer.
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
uint32_t m_DilationX
Dilation factor value for width dimension.
uint32_t m_PadTop
Padding top value in the height dimension.
Status SetViewSize(uint32_t view, uint32_t coord, uint32_t value)
Set the size of the views.
An output connection slot for a layer.
Definition: INetwork.hpp:37
A L2NormalizationDescriptor for the L2NormalizationLayer.
const ConstTensor * m_ProjectionBias
Definition: LstmParams.hpp:56
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:265
const ConstTensor * m_InputToForgetWeights
An ArgMinMaxDescriptor for ArgMinMaxLayer.
Definition: Descriptors.hpp:51
float GetQuantizationScale() const
Definition: Tensor.cpp:248
DataType GetDataType() const
Definition: Tensor.hpp:95
An OriginsDescriptor for the ConcatLayer.
float m_ProjectionClip
Clipping threshold value for the projection.
bool has_value() const noexcept
Definition: Optional.hpp:53
A FullyConnectedDescriptor for the FullyConnectedLayer.
bool m_BiasEnabled
Enable/disable bias.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:199
float m_InputIntermediateScale
Input intermediate quantization scale.
uint32_t m_TargetWidth
Target width value.
bool m_PeepholeEnabled
Enable/disable peephole.
uint32_t m_NumClasses
Number of classes.
uint32_t m_PadTop
Padding top value in the height dimension.
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:260
A StandInDescriptor for the StandIn layer.
A QLstmDescriptor for the QLstmLayer.
QuantizedType Quantize(float value, float scale, int32_t offset)
Quantize a floating point data type into an 8-bit data type.
Definition: TypesUtils.cpp:31
bool m_UseRegularNms
Use Regular NMS.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
void Resize(Decoder< float > &in, const TensorInfo &inputInfo, Encoder< float > &out, const TensorInfo &outputInfo, DataLayoutIndexed dataLayout, armnn::ResizeMethod resizeMethod, bool alignCorners)
Definition: Resize.cpp:35
void LogSoftmax(Decoder< float > &input, Encoder< float > &output, const TensorInfo &inputInfo, const LogSoftmaxDescriptor &descriptor)
Definition: LogSoftmax.cpp:30
const TensorInfo & GetInfo() const
Definition: Tensor.hpp:167
uint32_t m_TargetHeight
Target height value.
uint32_t m_ActivationFunc
The activation function to use.
A SliceDescriptor for the SliceLayer.
Visitor base class with empty implementations.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
void SpaceToBatchNd(const TensorInfo &inputInfo, const TensorInfo &outputInfo, const SpaceToBatchNdDescriptor &params, Decoder< float > &inputData, Encoder< float > &outputData)
bool SaveSerializedToStream(std::ostream &stream) override
Serializes the SerializedGraph to the stream.
const ConstTensor * m_RecurrentToInputWeights
float m_ClippingThresCell
Clipping threshold value for the cell state.
unsigned int m_BlockSize
Scalar specifying the input block size. It must be >= 1.
float m_ForgetIntermediateScale
Forget intermediate quantization scale.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
float m_ScaleH
Center size encoding scale height.
ComparisonOperation m_Operation
Specifies the comparison operation to execute.
Definition: Descriptors.hpp:86
const ConstTensor * m_CellLayerNormWeights
Definition: LstmParams.hpp:59
const ConstTensor * m_ForgetGateBias
Definition: LstmParams.hpp:52
A SpaceToBatchNdDescriptor for the SpaceToBatchNdLayer.
const ConstTensor * m_InputToCellWeights
Definition: LstmParams.hpp:42
const ConstTensor * m_InputToOutputWeights
Definition: LstmParams.hpp:43
float m_CellClip
Clipping threshold value for the cell state.
uint32_t m_DilationX
Dilation along x axis.
BOOST_AUTO_TEST_SUITE_END()
bool m_CifgEnabled
Enable/disable cifg (coupled input & forget gate).
uint32_t m_PadLeft
Padding left value in the width dimension.
void StridedSlice(const TensorInfo &inputInfo, const StridedSliceDescriptor &params, const void *inputData, void *outputData, unsigned int dataTypeSize)
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
const ConstTensor * m_RecurrentToForgetWeights
Definition: LstmParams.hpp:45
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
bool m_ProjectionEnabled
Enable/disable the projection layer.
const ConstTensor * m_RecurrentToCellWeights
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
const ConstTensor * m_RecurrentToInputWeights
Definition: LstmParams.hpp:44
A MeanDescriptor for the MeanLayer.
const ConstTensor * m_InputToOutputWeights
void Mean(const armnn::TensorInfo &inputInfo, const armnn::TensorInfo &outputInfo, const std::vector< unsigned int > &axis, Decoder< float > &input, Encoder< float > &output)
Definition: Mean.cpp:71
virtual const IOutputSlot * GetConnection() const =0
bool m_LayerNormEnabled
Enable/disable layer normalization.
uint32_t m_PadRight
Padding right value in the width dimension.
A TransposeDescriptor for the TransposeLayer.
A StridedSliceDescriptor for the StridedSliceLayer.
virtual const TensorInfo & GetTensorInfo() const =0
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
void SpaceToDepth(const TensorInfo &inputInfo, const TensorInfo &outputInfo, const SpaceToDepthDescriptor &params, Decoder< float > &inputData, Encoder< float > &outputData)
float m_ScaleY
Center size encoding scale y.
OriginsDescriptor CreateDescriptorForConcatenation(TensorShapeIt first, TensorShapeIt last, unsigned int concatenationDimension)
Convenience template to create an OriginsDescriptor to use when creating a ConcatLayer for performing...
#define DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(name)
float m_NmsScoreThreshold
NMS score threshold.
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:101
void BatchToSpaceNd(const DataLayoutIndexed &dataLayout, const TensorInfo &inputTensorInfo, const TensorInfo &outputTensorInfo, const std::vector< unsigned int > &blockShape, const std::vector< std::pair< unsigned int, unsigned int >> &cropsData, Decoder< float > &inputDecoder, Encoder< float > &outputEncoder)
virtual int Connect(IInputSlot &destination)=0
DataType GetDataType() const
Definition: Tensor.hpp:172
A Pooling2dDescriptor for the Pooling2dLayer.
const ConstTensor * m_OutputLayerNormWeights
Definition: LstmParams.hpp:60
A NormalizationDescriptor for the NormalizationLayer.
void Pooling2d(Decoder< float > &rInputDecoder, Encoder< float > &rOutputEncoder, const TensorInfo &inputInfo, const TensorInfo &outputInfo, const Pooling2dDescriptor &params)
Computes the Pooling2d operation.
Definition: Pooling2d.cpp:143
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
An InstanceNormalizationDescriptor for InstanceNormalizationLayer.
A ResizeBilinearDescriptor for the ResizeBilinearLayer.
void Splitter(const SplitterQueueDescriptor &data)
Definition: Splitter.hpp:17
float m_CellIntermediateScale
Cell intermediate quantization scale.
void Softmax(Decoder< float > &in, Encoder< float > &out, const TensorInfo &inputTensorInfo, float beta, int axis)
Computes the softmax function on some inputs, into outputs, with a shape given by tensorInfo...
Definition: Softmax.cpp:17
A SoftmaxDescriptor for the SoftmaxLayer.
bool m_CifgEnabled
Enable/disable CIFG (coupled input & forget gate).
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
Set the view origin coordinates.
static INetworkPtr Create()
Definition: Network.cpp:50
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
uint32_t m_PadLeft
Padding left value in the width dimension.
unsigned int GetNumBytes() const
Definition: Tensor.hpp:174
const ConstTensor * m_InputToForgetWeights
Definition: LstmParams.hpp:41
A PermuteDescriptor for the PermuteLayer.
uint32_t m_PadRight
Padding right value in the width dimension.
int32_t m_HiddenStateZeroPoint
Hidden State zero point.
const ConstTensor * m_InputToInputWeights
Definition: LstmParams.hpp:40
std::vector< float > anchors({ 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 100.5f, 1.0f, 1.0f })