blob: 6866391e0fcb2cd52345e3502ef4170be9e1e19e [file] [log] [blame]
Mike Kelly8c1701a2019-02-11 17:01:27 +00001//
Teresa Charlin52664732020-06-29 16:27:03 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
Mike Kelly8c1701a2019-02-11 17:01:27 +00003// SPDX-License-Identifier: MIT
4//
5
Mike Kelly8c1701a2019-02-11 17:01:27 +00006#include "../Serializer.hpp"
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +00007
Matthew Benthamff130e22020-01-17 11:47:42 +00008#include <armnn/Descriptors.hpp>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00009#include <armnn/INetwork.hpp>
Matthew Benthamff130e22020-01-17 11:47:42 +000010#include <armnn/TypesUtils.hpp>
11#include <armnn/LstmParams.hpp>
12#include <armnn/QuantizedLstmParams.hpp>
Derek Lamberti0028d1b2019-02-20 13:57:42 +000013#include <armnnDeserializer/IDeserializer.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000014
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +000015#include <random>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000016#include <vector>
17
Mike Kelly8c1701a2019-02-11 17:01:27 +000018#include <boost/test/unit_test.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000019
Derek Lamberti0028d1b2019-02-20 13:57:42 +000020using armnnDeserializer::IDeserializer;
Mike Kelly8c1701a2019-02-11 17:01:27 +000021
Saoirse Stewart3166c3e2019-02-18 15:24:53 +000022namespace
23{
24
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +010025#define DECLARE_LAYER_VERIFIER_CLASS(name) \
26class name##LayerVerifier : public LayerVerifierBase \
27{ \
28public: \
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) \
41class name##LayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::name##Descriptor> \
42{ \
43public: \
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
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000060struct DefaultLayerVerifierPolicy
61{
Derek Lamberti859f9ce2019-12-10 22:05:21 +000062 static void Apply(const std::string)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000063 {
64 BOOST_TEST_MESSAGE("Unexpected layer found in network");
65 BOOST_TEST(false);
66 }
67};
68
69class LayerVerifierBase : public armnn::LayerVisitorBase<DefaultLayerVerifierPolicy>
70{
71public:
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
Derek Lamberti859f9ce2019-12-10 22:05:21 +000081 void VisitOutputLayer(const armnn::IConnectableLayer*, armnn::LayerBindingId, const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000082
83protected:
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()));
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000100
101 BOOST_TEST(connectedInfo.GetQuantizationScale() == m_InputTensorInfos[i].GetQuantizationScale());
102 BOOST_TEST(connectedInfo.GetQuantizationOffset() == m_InputTensorInfos[i].GetQuantizationOffset());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000103 }
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()));
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000111
112 BOOST_TEST(outputInfo.GetQuantizationScale() == m_OutputTensorInfos[i].GetQuantizationScale());
113 BOOST_TEST(outputInfo.GetQuantizationOffset() == m_OutputTensorInfos[i].GetQuantizationOffset());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000114 }
115 }
116
Jan Eilers5b01a892019-07-23 09:47:43 +0100117 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
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000161private:
162 std::string m_LayerName;
163 std::vector<armnn::TensorInfo> m_InputTensorInfos;
164 std::vector<armnn::TensorInfo> m_OutputTensorInfos;
165};
166
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100167template<typename Descriptor>
168class LayerVerifierBaseWithDescriptor : public LayerVerifierBase
169{
170public:
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
178protected:
179 void VerifyDescriptor(const Descriptor& descriptor)
180 {
181 BOOST_CHECK(descriptor == m_Descriptor);
182 }
183
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100184 Descriptor m_Descriptor;
185};
186
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000187template<typename T>
188void 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
201void CompareConstTensor(const armnn::ConstTensor& tensor1, const armnn::ConstTensor& tensor2)
202{
203 BOOST_TEST(tensor1.GetShape() == tensor2.GetShape());
204 BOOST_TEST(GetDataTypeName(tensor1.GetDataType()) == GetDataTypeName(tensor2.GetDataType()));
205
206 switch (tensor1.GetDataType())
207 {
208 case armnn::DataType::Float32:
209 CompareConstTensorData<const float*>(
210 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
211 break;
Derek Lambertif90c56d2020-01-10 17:14:08 +0000212 case armnn::DataType::QAsymmU8:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000213 case armnn::DataType::Boolean:
214 CompareConstTensorData<const uint8_t*>(
215 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
216 break;
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000217 case armnn::DataType::QSymmS8:
218 CompareConstTensorData<const int8_t*>(
219 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
220 break;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000221 case armnn::DataType::Signed32:
222 CompareConstTensorData<const int32_t*>(
223 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
224 break;
225 default:
226 // Note that Float16 is not yet implemented
227 BOOST_TEST_MESSAGE("Unexpected datatype");
228 BOOST_TEST(false);
229 }
230}
231
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000232armnn::INetworkPtr DeserializeNetwork(const std::string& serializerString)
233{
234 std::vector<std::uint8_t> const serializerVector{serializerString.begin(), serializerString.end()};
Derek Lamberti0028d1b2019-02-20 13:57:42 +0000235 return IDeserializer::Create()->CreateNetworkFromBinary(serializerVector);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000236}
237
238std::string SerializeNetwork(const armnn::INetwork& network)
239{
240 armnnSerializer::Serializer serializer;
241 serializer.Serialize(network);
242
243 std::stringstream stream;
244 serializer.SaveSerializedToStream(stream);
245
246 std::string serializerString{stream.str()};
247 return serializerString;
248}
249
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000250template<typename DataType>
251static 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
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000271} // anonymous namespace
272
273BOOST_AUTO_TEST_SUITE(SerializerTests)
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000274
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000275BOOST_AUTO_TEST_CASE(SerializeAddition)
Mike Kelly8c1701a2019-02-11 17:01:27 +0000276{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100277 DECLARE_LAYER_VERIFIER_CLASS(Addition)
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000278
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000279 const std::string layerName("addition");
280 const armnn::TensorInfo tensorInfo({1, 2, 3}, armnn::DataType::Float32);
281
Mike Kelly8c1701a2019-02-11 17:01:27 +0000282 armnn::INetworkPtr network = armnn::INetwork::Create();
283 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
284 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000285 armnn::IConnectableLayer* const additionLayer = network->AddAdditionLayer(layerName.c_str());
286 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000287
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000288 inputLayer0->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(0));
289 inputLayer1->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(1));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000290 additionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Mike Kelly8c1701a2019-02-11 17:01:27 +0000291
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000292 inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
293 inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
294 additionLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
Jim Flynn3091b062019-02-15 14:45:04 +0000295
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000296 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000297 BOOST_CHECK(deserializedNetwork);
298
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000299 AdditionLayerVerifier verifier(layerName, {tensorInfo, tensorInfo}, {tensorInfo});
300 deserializedNetwork->Accept(verifier);
301}
Jim Flynnac25a1b2019-02-28 10:40:49 +0000302
Narumol Prangnawarat0cfcf232019-09-09 17:16:24 +0100303BOOST_AUTO_TEST_CASE(SerializeArgMinMax)
304{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100305 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(ArgMinMax)
Narumol Prangnawarat0cfcf232019-09-09 17:16:24 +0100306
307 const std::string layerName("argminmax");
308 const armnn::TensorInfo inputInfo({1, 2, 3}, armnn::DataType::Float32);
309 const armnn::TensorInfo outputInfo({1, 3}, armnn::DataType::Signed32);
310
311 armnn::ArgMinMaxDescriptor descriptor;
312 descriptor.m_Function = armnn::ArgMinMaxFunction::Max;
313 descriptor.m_Axis = 1;
314
315 armnn::INetworkPtr network = armnn::INetwork::Create();
316 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
317 armnn::IConnectableLayer* const argMinMaxLayer = network->AddArgMinMaxLayer(descriptor, layerName.c_str());
318 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
319
320 inputLayer->GetOutputSlot(0).Connect(argMinMaxLayer->GetInputSlot(0));
321 argMinMaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
322
323 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
324 argMinMaxLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
325
326 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
327 BOOST_CHECK(deserializedNetwork);
328
329 ArgMinMaxLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
330 deserializedNetwork->Accept(verifier);
331}
332
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000333BOOST_AUTO_TEST_CASE(SerializeBatchNormalization)
334{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100335 using Descriptor = armnn::BatchNormalizationDescriptor;
336 class BatchNormalizationLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000337 {
338 public:
339 BatchNormalizationLayerVerifier(const std::string& layerName,
340 const std::vector<armnn::TensorInfo>& inputInfos,
341 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100342 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000343 const armnn::ConstTensor& mean,
344 const armnn::ConstTensor& variance,
345 const armnn::ConstTensor& beta,
346 const armnn::ConstTensor& gamma)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100347 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
348 , m_Mean(mean)
349 , m_Variance(variance)
350 , m_Beta(beta)
351 , m_Gamma(gamma) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000352
353 void VisitBatchNormalizationLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100354 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000355 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:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000371 armnn::ConstTensor m_Mean;
372 armnn::ConstTensor m_Variance;
373 armnn::ConstTensor m_Beta;
374 armnn::ConstTensor m_Gamma;
375 };
376
377 const std::string layerName("batchNormalization");
378 const armnn::TensorInfo inputInfo ({ 1, 3, 3, 1 }, armnn::DataType::Float32);
379 const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
380
381 const armnn::TensorInfo meanInfo({1}, armnn::DataType::Float32);
382 const armnn::TensorInfo varianceInfo({1}, armnn::DataType::Float32);
383 const armnn::TensorInfo betaInfo({1}, armnn::DataType::Float32);
384 const armnn::TensorInfo gammaInfo({1}, armnn::DataType::Float32);
385
386 armnn::BatchNormalizationDescriptor descriptor;
387 descriptor.m_Eps = 0.0010000000475f;
388 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
389
390 std::vector<float> meanData({5.0});
391 std::vector<float> varianceData({2.0});
392 std::vector<float> betaData({1.0});
393 std::vector<float> gammaData({0.0});
394
395 armnn::ConstTensor mean(meanInfo, meanData);
396 armnn::ConstTensor variance(varianceInfo, varianceData);
397 armnn::ConstTensor beta(betaInfo, betaData);
398 armnn::ConstTensor gamma(gammaInfo, gammaData);
399
400 armnn::INetworkPtr network = armnn::INetwork::Create();
401 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
402 armnn::IConnectableLayer* const batchNormalizationLayer =
403 network->AddBatchNormalizationLayer(descriptor, mean, variance, beta, gamma, layerName.c_str());
404 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
405
406 inputLayer->GetOutputSlot(0).Connect(batchNormalizationLayer->GetInputSlot(0));
407 batchNormalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
408
409 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
410 batchNormalizationLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
411
412 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
413 BOOST_CHECK(deserializedNetwork);
414
415 BatchNormalizationLayerVerifier verifier(
416 layerName, {inputInfo}, {outputInfo}, descriptor, mean, variance, beta, gamma);
417 deserializedNetwork->Accept(verifier);
418}
419
420BOOST_AUTO_TEST_CASE(SerializeBatchToSpaceNd)
421{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100422 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(BatchToSpaceNd)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000423
424 const std::string layerName("spaceToBatchNd");
425 const armnn::TensorInfo inputInfo({4, 1, 2, 2}, armnn::DataType::Float32);
426 const armnn::TensorInfo outputInfo({1, 1, 4, 4}, armnn::DataType::Float32);
427
428 armnn::BatchToSpaceNdDescriptor desc;
429 desc.m_DataLayout = armnn::DataLayout::NCHW;
430 desc.m_BlockShape = {2, 2};
431 desc.m_Crops = {{0, 0}, {0, 0}};
432
433 armnn::INetworkPtr network = armnn::INetwork::Create();
434 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
435 armnn::IConnectableLayer* const batchToSpaceNdLayer = network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
436 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
437
438 inputLayer->GetOutputSlot(0).Connect(batchToSpaceNdLayer->GetInputSlot(0));
439 batchToSpaceNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
440
441 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
442 batchToSpaceNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
443
444 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
445 BOOST_CHECK(deserializedNetwork);
446
447 BatchToSpaceNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
448 deserializedNetwork->Accept(verifier);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000449}
450
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100451BOOST_AUTO_TEST_CASE(SerializeComparison)
452{
453 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Comparison)
454
455 const std::string layerName("comparison");
456
457 const armnn::TensorShape shape{2, 1, 2, 4};
458
459 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
460 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
461
462 armnn::ComparisonDescriptor descriptor(armnn::ComparisonOperation::NotEqual);
463
464 armnn::INetworkPtr network = armnn::INetwork::Create();
465 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
466 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
467 armnn::IConnectableLayer* const comparisonLayer = network->AddComparisonLayer(descriptor, layerName.c_str());
468 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
469
470 inputLayer0->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(0));
471 inputLayer1->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(1));
472 comparisonLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
473
474 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
475 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
476 comparisonLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
477
478 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
479 BOOST_CHECK(deserializedNetwork);
480
481 ComparisonLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo }, descriptor);
482 deserializedNetwork->Accept(verifier);
483}
484
Conor Kennedy76277882019-02-26 08:29:54 +0000485BOOST_AUTO_TEST_CASE(SerializeConstant)
486{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000487 class ConstantLayerVerifier : public LayerVerifierBase
Conor Kennedy76277882019-02-26 08:29:54 +0000488 {
489 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000490 ConstantLayerVerifier(const std::string& layerName,
491 const std::vector<armnn::TensorInfo>& inputInfos,
492 const std::vector<armnn::TensorInfo>& outputInfos,
493 const armnn::ConstTensor& layerInput)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100494 : LayerVerifierBase(layerName, inputInfos, outputInfos)
495 , m_LayerInput(layerInput) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000496
497 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
498 const armnn::ConstTensor& input,
499 const char* name) override
Conor Kennedy76277882019-02-26 08:29:54 +0000500 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000501 VerifyNameAndConnections(layer, name);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000502 CompareConstTensor(input, m_LayerInput);
Conor Kennedy76277882019-02-26 08:29:54 +0000503 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000504
Derek Lamberti859f9ce2019-12-10 22:05:21 +0000505 void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000506
507 private:
508 armnn::ConstTensor m_LayerInput;
Conor Kennedy76277882019-02-26 08:29:54 +0000509 };
510
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000511 const std::string layerName("constant");
512 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
Conor Kennedy76277882019-02-26 08:29:54 +0000513
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000514 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
515 armnn::ConstTensor constTensor(info, constantData);
Conor Kennedy76277882019-02-26 08:29:54 +0000516
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000517 armnn::INetworkPtr network(armnn::INetwork::Create());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000518 armnn::IConnectableLayer* input = network->AddInputLayer(0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000519 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000520 armnn::IConnectableLayer* add = network->AddAdditionLayer();
521 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
Conor Kennedy76277882019-02-26 08:29:54 +0000522
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
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000527 input->GetOutputSlot(0).SetTensorInfo(info);
528 constant->GetOutputSlot(0).SetTensorInfo(info);
529 add->GetOutputSlot(0).SetTensorInfo(info);
Conor Kennedy76277882019-02-26 08:29:54 +0000530
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000531 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Conor Kennedy76277882019-02-26 08:29:54 +0000532 BOOST_CHECK(deserializedNetwork);
533
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000534 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
535 deserializedNetwork->Accept(verifier);
Conor Kennedy76277882019-02-26 08:29:54 +0000536}
537
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000538BOOST_AUTO_TEST_CASE(SerializeConvolution2d)
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000539{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100540 using Descriptor = armnn::Convolution2dDescriptor;
541 class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000542 {
543 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000544 Convolution2dLayerVerifier(const std::string& layerName,
545 const std::vector<armnn::TensorInfo>& inputInfos,
546 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100547 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100548 const armnn::ConstTensor& weights,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100549 const armnn::Optional<armnn::ConstTensor>& biases)
550 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
551 , m_Weights(weights)
552 , m_Biases(biases) {}
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000553
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000554 void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100555 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100556 const armnn::ConstTensor& weights,
557 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000558 const char* name) override
559 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000560 VerifyNameAndConnections(layer, name);
561 VerifyDescriptor(descriptor);
562
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100563 // check weights
564 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000565
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100566 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100567 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100568 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
569
570 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000571 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100572 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000573 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000574 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000575
576 private:
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100577 armnn::ConstTensor m_Weights;
578 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000579 };
580
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000581 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);
Saoirse Stewart263829c2019-02-19 15:54:14 +0000584
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000585 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
586 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000587
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000588 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);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000593
594 armnn::Convolution2dDescriptor descriptor;
595 descriptor.m_PadLeft = 1;
596 descriptor.m_PadRight = 1;
597 descriptor.m_PadTop = 1;
598 descriptor.m_PadBottom = 1;
599 descriptor.m_StrideX = 2;
600 descriptor.m_StrideY = 2;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100601 descriptor.m_DilationX = 2;
602 descriptor.m_DilationY = 2;
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000603 descriptor.m_BiasEnabled = true;
604 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
605
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000606 armnn::INetworkPtr network = armnn::INetwork::Create();
607 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000608 armnn::IConnectableLayer* const convLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100609 network->AddConvolution2dLayer(descriptor,
610 weights,
611 armnn::Optional<armnn::ConstTensor>(biases),
612 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000613 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000614
615 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000616 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000617
618 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000619 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
620
621 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
622 BOOST_CHECK(deserializedNetwork);
623
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000624 Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
625 deserializedNetwork->Accept(verifier);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000626}
627
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000628BOOST_AUTO_TEST_CASE(SerializeConvolution2dWithPerAxisParams)
629{
630 using Descriptor = armnn::Convolution2dDescriptor;
631 class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
632 {
633 public:
634 Convolution2dLayerVerifier(const std::string& layerName,
635 const std::vector<armnn::TensorInfo>& inputInfos,
636 const std::vector<armnn::TensorInfo>& outputInfos,
637 const Descriptor& descriptor,
638 const armnn::ConstTensor& weights,
639 const armnn::Optional<armnn::ConstTensor>& biases)
640 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
641 , m_Weights(weights)
642 , m_Biases(biases) {}
643
644 void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
645 const Descriptor& descriptor,
646 const armnn::ConstTensor& weights,
647 const armnn::Optional<armnn::ConstTensor>& biases,
648 const char* name) override
649 {
650 VerifyNameAndConnections(layer, name);
651 VerifyDescriptor(descriptor);
652
653 // check weights
654 CompareConstTensor(weights, m_Weights);
655
656 // check biases
657 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
658 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
659
660 if (biases.has_value() && m_Biases.has_value())
661 {
662 CompareConstTensor(biases.value(), m_Biases.value());
663 }
664 }
665
666 private:
667 armnn::ConstTensor m_Weights;
668 armnn::Optional<armnn::ConstTensor> m_Biases;
669 };
670
671 using namespace armnn;
672
673 const std::string layerName("convolution2dWithPerAxis");
674 const TensorInfo inputInfo ({ 1, 3, 1, 2 }, DataType::QAsymmU8, 0.55f, 128);
675 const TensorInfo outputInfo({ 1, 3, 1, 3 }, DataType::QAsymmU8, 0.75f, 128);
676
677 const std::vector<float> quantScales{ 0.75f, 0.65f, 0.85f };
678 constexpr unsigned int quantDimension = 0;
679
680 const TensorInfo kernelInfo({ 3, 1, 1, 2 }, DataType::QSymmS8, quantScales, quantDimension);
681
682 const std::vector<float> biasQuantScales{ 0.25f, 0.50f, 0.75f };
683 const TensorInfo biasInfo({ 3 }, DataType::Signed32, biasQuantScales, quantDimension);
684
685 std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
686 armnn::ConstTensor weights(kernelInfo, kernelData);
687 std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
688 armnn::ConstTensor biases(biasInfo, biasData);
689
690 Convolution2dDescriptor descriptor;
691 descriptor.m_StrideX = 1;
692 descriptor.m_StrideY = 1;
693 descriptor.m_PadLeft = 0;
694 descriptor.m_PadRight = 0;
695 descriptor.m_PadTop = 0;
696 descriptor.m_PadBottom = 0;
697 descriptor.m_BiasEnabled = true;
698 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
699
700 armnn::INetworkPtr network = armnn::INetwork::Create();
701 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
702 armnn::IConnectableLayer* const convLayer =
703 network->AddConvolution2dLayer(descriptor,
704 weights,
705 armnn::Optional<armnn::ConstTensor>(biases),
706 layerName.c_str());
707 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
708
709 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
710 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
711
712 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
713 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
714
715 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
716 BOOST_CHECK(deserializedNetwork);
717
718 Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
719 deserializedNetwork->Accept(verifier);
720}
721
Aron Virginas-Tarda9d2d32019-09-20 10:42:02 +0100722BOOST_AUTO_TEST_CASE(SerializeDepthToSpace)
723{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100724 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(DepthToSpace)
Aron Virginas-Tarda9d2d32019-09-20 10:42:02 +0100725
726 const std::string layerName("depthToSpace");
727
728 const armnn::TensorInfo inputInfo ({ 1, 8, 4, 12 }, armnn::DataType::Float32);
729 const armnn::TensorInfo outputInfo({ 1, 16, 8, 3 }, armnn::DataType::Float32);
730
731 armnn::DepthToSpaceDescriptor desc;
732 desc.m_BlockSize = 2;
733 desc.m_DataLayout = armnn::DataLayout::NHWC;
734
735 armnn::INetworkPtr network = armnn::INetwork::Create();
736 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
737 armnn::IConnectableLayer* const depthToSpaceLayer = network->AddDepthToSpaceLayer(desc, layerName.c_str());
738 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
739
740 inputLayer->GetOutputSlot(0).Connect(depthToSpaceLayer->GetInputSlot(0));
741 depthToSpaceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
742
743 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
744 depthToSpaceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
745
746 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
747 BOOST_CHECK(deserializedNetwork);
748
749 DepthToSpaceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
750 deserializedNetwork->Accept(verifier);
751}
752
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000753BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2d)
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000754{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100755 using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
756 class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000757 {
758 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000759 DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
760 const std::vector<armnn::TensorInfo>& inputInfos,
761 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100762 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100763 const armnn::ConstTensor& weights,
764 const armnn::Optional<armnn::ConstTensor>& biases) :
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100765 LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100766 m_Weights(weights),
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100767 m_Biases(biases) {}
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000768
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000769 void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100770 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100771 const armnn::ConstTensor& weights,
772 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000773 const char* name) override
774 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000775 VerifyNameAndConnections(layer, name);
776 VerifyDescriptor(descriptor);
777
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100778 // check weights
779 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000780
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100781 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100782 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100783 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
784
785 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000786 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100787 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000788 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000789 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000790
791 private:
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100792 armnn::ConstTensor m_Weights;
793 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000794 };
795
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000796 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);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000799
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000800 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
801 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000802
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
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000809 armnn::DepthwiseConvolution2dDescriptor descriptor;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100810 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;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000818 descriptor.m_BiasEnabled = true;
819 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
820
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000821 armnn::INetworkPtr network = armnn::INetwork::Create();
822 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
823 armnn::IConnectableLayer* const depthwiseConvLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100824 network->AddDepthwiseConvolution2dLayer(descriptor,
825 weights,
826 armnn::Optional<armnn::ConstTensor>(biases),
827 layerName.c_str());
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000828 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
829
830 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000831 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000832
833 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000834 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
835
836 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
837 BOOST_CHECK(deserializedNetwork);
838
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000839 DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
840 deserializedNetwork->Accept(verifier);
Jim Flynn18ce3382019-03-08 11:08:30 +0000841}
842
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000843BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2dWithPerAxisParams)
844{
845 using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
846 class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
847 {
848 public:
849 DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
850 const std::vector<armnn::TensorInfo>& inputInfos,
851 const std::vector<armnn::TensorInfo>& outputInfos,
852 const Descriptor& descriptor,
853 const armnn::ConstTensor& weights,
854 const armnn::Optional<armnn::ConstTensor>& biases) :
855 LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
856 m_Weights(weights),
857 m_Biases(biases) {}
858
859 void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
860 const Descriptor& descriptor,
861 const armnn::ConstTensor& weights,
862 const armnn::Optional<armnn::ConstTensor>& biases,
863 const char* name) override
864 {
865 VerifyNameAndConnections(layer, name);
866 VerifyDescriptor(descriptor);
867
868 // check weights
869 CompareConstTensor(weights, m_Weights);
870
871 // check biases
872 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
873 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
874
875 if (biases.has_value() && m_Biases.has_value())
876 {
877 CompareConstTensor(biases.value(), m_Biases.value());
878 }
879 }
880
881 private:
882 armnn::ConstTensor m_Weights;
883 armnn::Optional<armnn::ConstTensor> m_Biases;
884 };
885
886 using namespace armnn;
887
888 const std::string layerName("depwiseConvolution2dWithPerAxis");
889 const TensorInfo inputInfo ({ 1, 3, 3, 2 }, DataType::QAsymmU8, 0.55f, 128);
890 const TensorInfo outputInfo({ 1, 2, 2, 4 }, DataType::QAsymmU8, 0.75f, 128);
891
892 const std::vector<float> quantScales{ 0.75f, 0.80f, 0.90f, 0.95f };
893 const unsigned int quantDimension = 0;
894 TensorInfo kernelInfo({ 2, 2, 2, 2 }, DataType::QSymmS8, quantScales, quantDimension);
895
896 const std::vector<float> biasQuantScales{ 0.25f, 0.35f, 0.45f, 0.55f };
897 constexpr unsigned int biasQuantDimension = 0;
898 TensorInfo biasInfo({ 4 }, DataType::Signed32, biasQuantScales, biasQuantDimension);
899
900 std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
901 armnn::ConstTensor weights(kernelInfo, kernelData);
902 std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
903 armnn::ConstTensor biases(biasInfo, biasData);
904
905 DepthwiseConvolution2dDescriptor descriptor;
906 descriptor.m_StrideX = 1;
907 descriptor.m_StrideY = 1;
908 descriptor.m_PadLeft = 0;
909 descriptor.m_PadRight = 0;
910 descriptor.m_PadTop = 0;
911 descriptor.m_PadBottom = 0;
912 descriptor.m_DilationX = 1;
913 descriptor.m_DilationY = 1;
914 descriptor.m_BiasEnabled = true;
915 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
916
917 armnn::INetworkPtr network = armnn::INetwork::Create();
918 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
919 armnn::IConnectableLayer* const depthwiseConvLayer =
920 network->AddDepthwiseConvolution2dLayer(descriptor,
921 weights,
922 armnn::Optional<armnn::ConstTensor>(biases),
923 layerName.c_str());
924 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
925
926 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
927 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
928
929 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
930 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
931
932 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
933 BOOST_CHECK(deserializedNetwork);
934
935 DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
936 deserializedNetwork->Accept(verifier);
937}
938
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000939BOOST_AUTO_TEST_CASE(SerializeDequantize)
940{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100941 DECLARE_LAYER_VERIFIER_CLASS(Dequantize)
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000942
943 const std::string layerName("dequantize");
Derek Lambertif90c56d2020-01-10 17:14:08 +0000944 const armnn::TensorInfo inputInfo({ 1, 5, 2, 3 }, armnn::DataType::QAsymmU8, 0.5f, 1);
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000945 const armnn::TensorInfo outputInfo({ 1, 5, 2, 3 }, armnn::DataType::Float32);
946
947 armnn::INetworkPtr network = armnn::INetwork::Create();
948 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
949 armnn::IConnectableLayer* const dequantizeLayer = network->AddDequantizeLayer(layerName.c_str());
950 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
951
952 inputLayer->GetOutputSlot(0).Connect(dequantizeLayer->GetInputSlot(0));
953 dequantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
954
955 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
956 dequantizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
957
958 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
959 BOOST_CHECK(deserializedNetwork);
960
961 DequantizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
962 deserializedNetwork->Accept(verifier);
963}
964
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000965BOOST_AUTO_TEST_CASE(SerializeDeserializeDetectionPostProcess)
966{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100967 using Descriptor = armnn::DetectionPostProcessDescriptor;
968 class DetectionPostProcessLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000969 {
970 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000971 DetectionPostProcessLayerVerifier(const std::string& layerName,
972 const std::vector<armnn::TensorInfo>& inputInfos,
973 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100974 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000975 const armnn::ConstTensor& anchors)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100976 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
977 , m_Anchors(anchors) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000978
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000979 void VisitDetectionPostProcessLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100980 const Descriptor& descriptor,
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000981 const armnn::ConstTensor& anchors,
982 const char* name) override
983 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000984 VerifyNameAndConnections(layer, name);
985 VerifyDescriptor(descriptor);
986
987 CompareConstTensor(anchors, m_Anchors);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000988 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000989
990 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000991 armnn::ConstTensor m_Anchors;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000992 };
993
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000994 const std::string layerName("detectionPostProcess");
995
996 const std::vector<armnn::TensorInfo> inputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000997 armnn::TensorInfo({ 1, 6, 4 }, armnn::DataType::Float32),
998 armnn::TensorInfo({ 1, 6, 3}, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000999 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001000
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001001 const std::vector<armnn::TensorInfo> outputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001002 armnn::TensorInfo({ 1, 3, 4 }, armnn::DataType::Float32),
1003 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1004 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1005 armnn::TensorInfo({ 1 }, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001006 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001007
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001008 armnn::DetectionPostProcessDescriptor descriptor;
1009 descriptor.m_UseRegularNms = true;
1010 descriptor.m_MaxDetections = 3;
1011 descriptor.m_MaxClassesPerDetection = 1;
1012 descriptor.m_DetectionsPerClass =1;
1013 descriptor.m_NmsScoreThreshold = 0.0;
1014 descriptor.m_NmsIouThreshold = 0.5;
1015 descriptor.m_NumClasses = 2;
1016 descriptor.m_ScaleY = 10.0;
1017 descriptor.m_ScaleX = 10.0;
1018 descriptor.m_ScaleH = 5.0;
1019 descriptor.m_ScaleW = 5.0;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001020
1021 const armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32);
1022 const std::vector<float> anchorsData({
1023 0.5f, 0.5f, 1.0f, 1.0f,
1024 0.5f, 0.5f, 1.0f, 1.0f,
1025 0.5f, 0.5f, 1.0f, 1.0f,
1026 0.5f, 10.5f, 1.0f, 1.0f,
1027 0.5f, 10.5f, 1.0f, 1.0f,
1028 0.5f, 100.5f, 1.0f, 1.0f
1029 });
1030 armnn::ConstTensor anchors(anchorsInfo, anchorsData);
1031
1032 armnn::INetworkPtr network = armnn::INetwork::Create();
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001033 armnn::IConnectableLayer* const detectionLayer =
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001034 network->AddDetectionPostProcessLayer(descriptor, anchors, layerName.c_str());
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001035
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
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001053 DetectionPostProcessLayerVerifier verifier(layerName, inputInfos, outputInfos, descriptor, anchors);
1054 deserializedNetwork->Accept(verifier);
1055}
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001056
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001057BOOST_AUTO_TEST_CASE(SerializeDivision)
1058{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001059 DECLARE_LAYER_VERIFIER_CLASS(Division)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001060
1061 const std::string layerName("division");
1062 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1063
1064 armnn::INetworkPtr network = armnn::INetwork::Create();
1065 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1066 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1067 armnn::IConnectableLayer* const divisionLayer = network->AddDivisionLayer(layerName.c_str());
1068 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1069
1070 inputLayer0->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(0));
1071 inputLayer1->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(1));
1072 divisionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1073
1074 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1075 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1076 divisionLayer->GetOutputSlot(0).SetTensorInfo(info);
1077
1078 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1079 BOOST_CHECK(deserializedNetwork);
1080
1081 DivisionLayerVerifier verifier(layerName, {info, info}, {info});
1082 deserializedNetwork->Accept(verifier);
1083}
1084
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001085class EqualLayerVerifier : public LayerVerifierBase
1086{
1087public:
1088 EqualLayerVerifier(const std::string& layerName,
1089 const std::vector<armnn::TensorInfo>& inputInfos,
1090 const std::vector<armnn::TensorInfo>& outputInfos)
1091 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1092
1093 void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1094 const armnn::ComparisonDescriptor& descriptor,
1095 const char* name) override
1096 {
1097 VerifyNameAndConnections(layer, name);
1098 BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Equal);
1099 }
1100
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001101 void VisitEqualLayer(const armnn::IConnectableLayer*, const char*) override
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001102 {
1103 throw armnn::Exception("EqualLayer should have translated to ComparisonLayer");
1104 }
1105};
1106
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001107// 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
1110BOOST_AUTO_TEST_CASE(SerializeEqual)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001111{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001112 const std::string layerName("equal");
1113
1114 const armnn::TensorShape shape{2, 1, 2, 4};
1115
1116 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1117 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1118
1119 armnn::INetworkPtr network = armnn::INetwork::Create();
1120 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1121 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1122 ARMNN_NO_DEPRECATE_WARN_BEGIN
1123 armnn::IConnectableLayer* const equalLayer = network->AddEqualLayer(layerName.c_str());
1124 ARMNN_NO_DEPRECATE_WARN_END
1125 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1126
1127 inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1128 inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1129 equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1130
1131 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1132 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1133 equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1134
1135 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1136 BOOST_CHECK(deserializedNetwork);
1137
1138 EqualLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1139 deserializedNetwork->Accept(verifier);
1140}
1141
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001142BOOST_AUTO_TEST_CASE(EnsureEqualBackwardCompatibility)
1143{
1144 // The hex data below is a flat buffer containing a simple network with two inputs,
1145 // an EqualLayer (now deprecated) and an output
1146 //
1147 // This test verifies that we can still deserialize this old-style model by replacing
1148 // the EqualLayer with an equivalent ComparisonLayer
1149 const std::vector<uint8_t> equalModel =
1150 {
1151 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1152 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1153 0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1155 0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1156 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1157 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1159 0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1160 0x00, 0x13, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1161 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1162 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1163 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1164 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1165 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
1166 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1167 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1168 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1169 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1170 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1171 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1172 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1173 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1175 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1176 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1177 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
1178 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1179 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1180 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1181 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1182 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1183 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1184 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1185 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1186 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1187 0x04, 0x00, 0x00, 0x00
1188 };
1189
1190 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(equalModel.begin(), equalModel.end()));
1191 BOOST_CHECK(deserializedNetwork);
1192
1193 const armnn::TensorShape shape{ 2, 1, 2, 4 };
1194
1195 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1196 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1197
1198 EqualLayerVerifier verifier("equal", { inputInfo, inputInfo }, { outputInfo });
1199 deserializedNetwork->Accept(verifier);
1200}
1201
Keith Davis300ad562020-06-04 16:34:23 +01001202BOOST_AUTO_TEST_CASE(SerializeFill)
1203{
1204 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Fill)
1205
1206 const std::string layerName("fill");
Teresa Charlin4b10fef2020-07-29 09:36:41 +01001207 const armnn::TensorInfo inputInfo({4}, armnn::DataType::Signed32);
Keith Davis300ad562020-06-04 16:34:23 +01001208 const armnn::TensorInfo outputInfo({1, 3, 3, 1}, armnn::DataType::Float32);
1209
1210 armnn::FillDescriptor descriptor(1.0f);
1211
1212 armnn::INetworkPtr network = armnn::INetwork::Create();
1213 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1214 armnn::IConnectableLayer* const fillLayer = network->AddFillLayer(descriptor, layerName.c_str());
1215 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1216
1217 inputLayer->GetOutputSlot(0).Connect(fillLayer->GetInputSlot(0));
1218 fillLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1219
1220 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1221 fillLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1222
1223 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1224 BOOST_CHECK(deserializedNetwork);
1225
1226 FillLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1227
1228 deserializedNetwork->Accept(verifier);
1229}
1230
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001231BOOST_AUTO_TEST_CASE(SerializeFloor)
1232{
1233 DECLARE_LAYER_VERIFIER_CLASS(Floor)
1234
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001235 const std::string layerName("floor");
1236 const armnn::TensorInfo info({4,4}, armnn::DataType::Float32);
1237
1238 armnn::INetworkPtr network = armnn::INetwork::Create();
1239 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1240 armnn::IConnectableLayer* const floorLayer = network->AddFloorLayer(layerName.c_str());
1241 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1242
1243 inputLayer->GetOutputSlot(0).Connect(floorLayer->GetInputSlot(0));
1244 floorLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1245
1246 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1247 floorLayer->GetOutputSlot(0).SetTensorInfo(info);
1248
1249 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1250 BOOST_CHECK(deserializedNetwork);
1251
1252 FloorLayerVerifier verifier(layerName, {info}, {info});
1253 deserializedNetwork->Accept(verifier);
1254}
1255
1256BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
1257{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001258 using Descriptor = armnn::FullyConnectedDescriptor;
1259 class FullyConnectedLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001260 {
1261 public:
1262 FullyConnectedLayerVerifier(const std::string& layerName,
1263 const std::vector<armnn::TensorInfo>& inputInfos,
1264 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001265 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001266 const armnn::ConstTensor& weight,
1267 const armnn::Optional<armnn::ConstTensor>& bias)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001268 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
1269 , m_Weight(weight)
1270 , m_Bias(bias) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001271
1272 void VisitFullyConnectedLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001273 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001274 const armnn::ConstTensor& weight,
1275 const armnn::Optional<armnn::ConstTensor>& bias,
1276 const char* name) override
1277 {
1278 VerifyNameAndConnections(layer, name);
1279 VerifyDescriptor(descriptor);
1280
1281 CompareConstTensor(weight, m_Weight);
1282
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001283 BOOST_TEST(bias.has_value() == descriptor.m_BiasEnabled);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001284 BOOST_TEST(bias.has_value() == m_Bias.has_value());
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001285
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001286 if (bias.has_value() && m_Bias.has_value())
1287 {
1288 CompareConstTensor(bias.value(), m_Bias.value());
1289 }
1290 }
1291
1292 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001293 armnn::ConstTensor m_Weight;
1294 armnn::Optional<armnn::ConstTensor> m_Bias;
1295 };
1296
1297 const std::string layerName("fullyConnected");
1298 const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
1299 const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
1300
1301 const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
1302 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
1303 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
1304 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
1305 armnn::ConstTensor weights(weightsInfo, weightsData);
1306 armnn::ConstTensor biases(biasesInfo, biasesData);
1307
1308 armnn::FullyConnectedDescriptor descriptor;
1309 descriptor.m_BiasEnabled = true;
1310 descriptor.m_TransposeWeightMatrix = false;
1311
1312 armnn::INetworkPtr network = armnn::INetwork::Create();
1313 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1314 armnn::IConnectableLayer* const fullyConnectedLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +01001315 network->AddFullyConnectedLayer(descriptor,
1316 weights,
1317 armnn::Optional<armnn::ConstTensor>(biases),
1318 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001319 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1320
1321 inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
1322 fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1323
1324 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1325 fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1326
1327 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1328 BOOST_CHECK(deserializedNetwork);
1329
1330 FullyConnectedLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
1331 deserializedNetwork->Accept(verifier);
1332}
1333
1334BOOST_AUTO_TEST_CASE(SerializeGather)
1335{
Teresa Charlin52664732020-06-29 16:27:03 +01001336 using GatherDescriptor = armnn::GatherDescriptor;
1337 class GatherLayerVerifier : public LayerVerifierBaseWithDescriptor<GatherDescriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001338 {
1339 public:
1340 GatherLayerVerifier(const std::string& layerName,
1341 const std::vector<armnn::TensorInfo>& inputInfos,
Teresa Charlin52664732020-06-29 16:27:03 +01001342 const std::vector<armnn::TensorInfo>& outputInfos,
1343 const GatherDescriptor& descriptor)
1344 : LayerVerifierBaseWithDescriptor<GatherDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001345
Teresa Charlin52664732020-06-29 16:27:03 +01001346 void VisitGatherLayer(const armnn::IConnectableLayer* layer,
1347 const GatherDescriptor& descriptor,
1348 const char *name) override
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001349 {
1350 VerifyNameAndConnections(layer, name);
Teresa Charlin52664732020-06-29 16:27:03 +01001351 BOOST_CHECK(descriptor.m_Axis == m_Descriptor.m_Axis);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001352 }
1353
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001354 void VisitConstantLayer(const armnn::IConnectableLayer*,
1355 const armnn::ConstTensor&,
1356 const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001357 };
1358
1359 const std::string layerName("gather");
Derek Lambertif90c56d2020-01-10 17:14:08 +00001360 armnn::TensorInfo paramsInfo({ 8 }, armnn::DataType::QAsymmU8);
1361 armnn::TensorInfo outputInfo({ 3 }, armnn::DataType::QAsymmU8);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001362 const armnn::TensorInfo indicesInfo({ 3 }, armnn::DataType::Signed32);
Teresa Charlin52664732020-06-29 16:27:03 +01001363 GatherDescriptor descriptor;
1364 descriptor.m_Axis = 1;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001365
1366 paramsInfo.SetQuantizationScale(1.0f);
1367 paramsInfo.SetQuantizationOffset(0);
1368 outputInfo.SetQuantizationScale(1.0f);
1369 outputInfo.SetQuantizationOffset(0);
1370
1371 const std::vector<int32_t>& indicesData = {7, 6, 5};
1372
1373 armnn::INetworkPtr network = armnn::INetwork::Create();
1374 armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
1375 armnn::IConnectableLayer *const constantLayer =
1376 network->AddConstantLayer(armnn::ConstTensor(indicesInfo, indicesData));
Teresa Charlin52664732020-06-29 16:27:03 +01001377 armnn::IConnectableLayer *const gatherLayer = network->AddGatherLayer(descriptor, layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001378 armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
1379
1380 inputLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(0));
1381 constantLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(1));
1382 gatherLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1383
1384 inputLayer->GetOutputSlot(0).SetTensorInfo(paramsInfo);
1385 constantLayer->GetOutputSlot(0).SetTensorInfo(indicesInfo);
1386 gatherLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1387
1388 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1389 BOOST_CHECK(deserializedNetwork);
1390
Teresa Charlin52664732020-06-29 16:27:03 +01001391 GatherLayerVerifier verifier(layerName, {paramsInfo, indicesInfo}, {outputInfo}, descriptor);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001392 deserializedNetwork->Accept(verifier);
1393}
1394
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001395class GreaterLayerVerifier : public LayerVerifierBase
1396{
1397public:
1398 GreaterLayerVerifier(const std::string& layerName,
1399 const std::vector<armnn::TensorInfo>& inputInfos,
1400 const std::vector<armnn::TensorInfo>& outputInfos)
1401 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1402
1403 void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1404 const armnn::ComparisonDescriptor& descriptor,
1405 const char* name) override
1406 {
1407 VerifyNameAndConnections(layer, name);
1408 BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Greater);
1409 }
1410
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001411 void VisitGreaterLayer(const armnn::IConnectableLayer*, const char*) override
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001412 {
1413 throw armnn::Exception("GreaterLayer should have translated to ComparisonLayer");
1414 }
1415};
1416
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001417// NOTE: Until the deprecated AddGreaterLayer disappears this test checks that calling
1418// AddGreaterLayer places a ComparisonLayer into the serialized format and that
1419// when this deserialises we have a ComparisonLayer
1420BOOST_AUTO_TEST_CASE(SerializeGreater)
Aron Virginas-Tar781ced92019-10-03 11:15:39 +01001421{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001422 const std::string layerName("greater");
1423
1424 const armnn::TensorShape shape{2, 1, 2, 4};
1425
1426 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1427 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1428
1429 armnn::INetworkPtr network = armnn::INetwork::Create();
1430 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1431 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1432 ARMNN_NO_DEPRECATE_WARN_BEGIN
1433 armnn::IConnectableLayer* const equalLayer = network->AddGreaterLayer(layerName.c_str());
1434 ARMNN_NO_DEPRECATE_WARN_END
1435 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1436
1437 inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1438 inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1439 equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1440
1441 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1442 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1443 equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1444
1445 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1446 BOOST_CHECK(deserializedNetwork);
1447
1448 GreaterLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1449 deserializedNetwork->Accept(verifier);
1450}
1451
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001452BOOST_AUTO_TEST_CASE(EnsureGreaterBackwardCompatibility)
1453{
1454 // The hex data below is a flat buffer containing a simple network with two inputs,
1455 // an GreaterLayer (now deprecated) and an output
1456 //
1457 // This test verifies that we can still deserialize this old-style model by replacing
1458 // the GreaterLayer with an equivalent ComparisonLayer
1459 const std::vector<uint8_t> greaterModel =
1460 {
1461 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1462 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1463 0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1465 0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1466 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1467 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1469 0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1470 0x00, 0x19, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1471 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1472 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x00, 0x02, 0x00, 0x00, 0x00,
1473 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1474 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1475 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1476 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1477 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1478 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1479 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1480 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1481 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1482 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1483 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1485 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1486 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1487 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1488 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1489 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1490 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1491 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1492 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1493 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1494 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1495 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1496 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1497 0x02, 0x00, 0x00, 0x00
1498 };
1499
1500 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(greaterModel.begin(), greaterModel.end()));
1501 BOOST_CHECK(deserializedNetwork);
1502
1503 const armnn::TensorShape shape{ 1, 2, 2, 2 };
1504
1505 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1506 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1507
1508 GreaterLayerVerifier verifier("greater", { inputInfo, inputInfo }, { outputInfo });
1509 deserializedNetwork->Accept(verifier);
1510}
1511
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001512BOOST_AUTO_TEST_CASE(SerializeInstanceNormalization)
1513{
1514 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(InstanceNormalization)
1515
Aron Virginas-Tar781ced92019-10-03 11:15:39 +01001516 const std::string layerName("instanceNormalization");
1517 const armnn::TensorInfo info({ 1, 2, 1, 5 }, armnn::DataType::Float32);
1518
1519 armnn::InstanceNormalizationDescriptor descriptor;
1520 descriptor.m_Gamma = 1.1f;
1521 descriptor.m_Beta = 0.1f;
1522 descriptor.m_Eps = 0.0001f;
1523 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
1524
1525 armnn::INetworkPtr network = armnn::INetwork::Create();
1526 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1527 armnn::IConnectableLayer* const instanceNormLayer =
1528 network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1529 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1530
1531 inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1532 instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1533
1534 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1535 instanceNormLayer->GetOutputSlot(0).SetTensorInfo(info);
1536
1537 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1538 BOOST_CHECK(deserializedNetwork);
1539
1540 InstanceNormalizationLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1541 deserializedNetwork->Accept(verifier);
1542}
1543
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001544DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(L2Normalization)
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001545
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001546BOOST_AUTO_TEST_CASE(SerializeL2Normalization)
1547{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001548 const std::string l2NormLayerName("l2Normalization");
1549 const armnn::TensorInfo info({1, 2, 1, 5}, armnn::DataType::Float32);
1550
1551 armnn::L2NormalizationDescriptor desc;
1552 desc.m_DataLayout = armnn::DataLayout::NCHW;
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001553 desc.m_Eps = 0.0001f;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001554
1555 armnn::INetworkPtr network = armnn::INetwork::Create();
1556 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1557 armnn::IConnectableLayer* const l2NormLayer = network->AddL2NormalizationLayer(desc, l2NormLayerName.c_str());
1558 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1559
1560 inputLayer0->GetOutputSlot(0).Connect(l2NormLayer->GetInputSlot(0));
1561 l2NormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1562
1563 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1564 l2NormLayer->GetOutputSlot(0).SetTensorInfo(info);
1565
1566 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1567 BOOST_CHECK(deserializedNetwork);
1568
1569 L2NormalizationLayerVerifier verifier(l2NormLayerName, {info}, {info}, desc);
1570 deserializedNetwork->Accept(verifier);
1571}
1572
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001573BOOST_AUTO_TEST_CASE(EnsureL2NormalizationBackwardCompatibility)
1574{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001575 // The hex data below is a flat buffer containing a simple network with one input
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001576 // a L2Normalization layer and an output layer with dimensions as per the tensor infos below.
1577 //
1578 // This test verifies that we can still read back these old style
1579 // models without the normalization epsilon value.
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001580 const std::vector<uint8_t> l2NormalizationModel =
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001581 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001582 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1583 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1584 0x3C, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1585 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
1586 0x04, 0x00, 0x00, 0x00, 0xD6, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
1587 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
1588 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1590 0x4C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1591 0x00, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1592 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1593 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1594 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x20, 0x00,
1595 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x6C, 0x32, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x61, 0x74,
1596 0x69, 0x6F, 0x6E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00,
1597 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1598 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
1599 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1600 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1601 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1602 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1603 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1604 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1605 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1606 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1607 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1608 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1609 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1610 0x05, 0x00, 0x00, 0x00, 0x00
1611 };
1612
1613 armnn::INetworkPtr deserializedNetwork =
1614 DeserializeNetwork(std::string(l2NormalizationModel.begin(), l2NormalizationModel.end()));
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001615 BOOST_CHECK(deserializedNetwork);
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001616
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001617 const std::string layerName("l2Normalization");
1618 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 2, 1, 5}, armnn::DataType::Float32);
1619
1620 armnn::L2NormalizationDescriptor desc;
1621 desc.m_DataLayout = armnn::DataLayout::NCHW;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001622 // Since this variable does not exist in the l2NormalizationModel dump, the default value will be loaded
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001623 desc.m_Eps = 1e-12f;
1624
1625 L2NormalizationLayerVerifier verifier(layerName, {inputInfo}, {inputInfo}, desc);
1626 deserializedNetwork->Accept(verifier);
1627}
1628
James Conroyaba90cd2020-11-06 16:28:18 +00001629BOOST_AUTO_TEST_CASE(SerializeLogicalBinary)
1630{
1631 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(LogicalBinary)
1632
1633 const std::string layerName("logicalBinaryAnd");
1634
1635 const armnn::TensorShape shape{2, 1, 2, 2};
1636
1637 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1638 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1639
1640 armnn::LogicalBinaryDescriptor descriptor(armnn::LogicalBinaryOperation::LogicalAnd);
1641
1642 armnn::INetworkPtr network = armnn::INetwork::Create();
1643 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1644 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1645 armnn::IConnectableLayer* const logicalBinaryLayer = network->AddLogicalBinaryLayer(descriptor, layerName.c_str());
1646 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1647
1648 inputLayer0->GetOutputSlot(0).Connect(logicalBinaryLayer->GetInputSlot(0));
1649 inputLayer1->GetOutputSlot(0).Connect(logicalBinaryLayer->GetInputSlot(1));
1650 logicalBinaryLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1651
1652 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1653 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1654 logicalBinaryLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1655
1656 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1657 BOOST_CHECK(deserializedNetwork);
1658
1659 LogicalBinaryLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo }, descriptor);
1660 deserializedNetwork->Accept(verifier);
1661}
1662
1663BOOST_AUTO_TEST_CASE(SerializeLogicalUnary)
1664{
1665 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(ElementwiseUnary)
1666
1667 const std::string layerName("elementwiseUnaryLogicalNot");
1668
1669 const armnn::TensorShape shape{2, 1, 2, 2};
1670
1671 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1672 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1673
1674 armnn::ElementwiseUnaryDescriptor descriptor(armnn::UnaryOperation::LogicalNot);
1675
1676 armnn::INetworkPtr network = armnn::INetwork::Create();
1677 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1678 armnn::IConnectableLayer* const elementwiseUnaryLayer =
1679 network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
1680 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1681
1682 inputLayer->GetOutputSlot(0).Connect(elementwiseUnaryLayer->GetInputSlot(0));
1683 elementwiseUnaryLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1684
1685 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1686 elementwiseUnaryLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1687
1688 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1689
1690 BOOST_CHECK(deserializedNetwork);
1691
1692 ElementwiseUnaryLayerVerifier verifier(layerName, { inputInfo }, { outputInfo }, descriptor);
1693
1694 deserializedNetwork->Accept(verifier);
1695}
1696
Sadik Armagan26257852019-10-14 13:00:47 +01001697BOOST_AUTO_TEST_CASE(SerializeLogSoftmax)
1698{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001699 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(LogSoftmax)
Sadik Armagan26257852019-10-14 13:00:47 +01001700
1701 const std::string layerName("log_softmax");
1702 const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
1703
1704 armnn::LogSoftmaxDescriptor descriptor;
1705 descriptor.m_Beta = 1.0f;
1706 descriptor.m_Axis = -1;
1707
1708 armnn::INetworkPtr network = armnn::INetwork::Create();
1709 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1710 armnn::IConnectableLayer* const logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
1711 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1712
1713 inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
1714 logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1715
1716 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1717 logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
1718
1719 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1720 BOOST_CHECK(deserializedNetwork);
1721
1722 LogSoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1723 deserializedNetwork->Accept(verifier);
1724}
1725
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001726BOOST_AUTO_TEST_CASE(SerializeMaximum)
1727{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001728 DECLARE_LAYER_VERIFIER_CLASS(Maximum)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001729
1730 const std::string layerName("maximum");
1731 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1732
1733 armnn::INetworkPtr network = armnn::INetwork::Create();
1734 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1735 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1736 armnn::IConnectableLayer* const maximumLayer = network->AddMaximumLayer(layerName.c_str());
1737 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1738
1739 inputLayer0->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(0));
1740 inputLayer1->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(1));
1741 maximumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1742
1743 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1744 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1745 maximumLayer->GetOutputSlot(0).SetTensorInfo(info);
1746
1747 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1748 BOOST_CHECK(deserializedNetwork);
1749
1750 MaximumLayerVerifier verifier(layerName, {info, info}, {info});
1751 deserializedNetwork->Accept(verifier);
1752}
1753
1754BOOST_AUTO_TEST_CASE(SerializeMean)
1755{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001756 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Mean)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001757
1758 const std::string layerName("mean");
1759 const armnn::TensorInfo inputInfo({1, 1, 3, 2}, armnn::DataType::Float32);
1760 const armnn::TensorInfo outputInfo({1, 1, 1, 2}, armnn::DataType::Float32);
1761
1762 armnn::MeanDescriptor descriptor;
1763 descriptor.m_Axis = { 2 };
1764 descriptor.m_KeepDims = true;
1765
1766 armnn::INetworkPtr network = armnn::INetwork::Create();
1767 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1768 armnn::IConnectableLayer* const meanLayer = network->AddMeanLayer(descriptor, layerName.c_str());
1769 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1770
1771 inputLayer->GetOutputSlot(0).Connect(meanLayer->GetInputSlot(0));
1772 meanLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1773
1774 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1775 meanLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1776
1777 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1778 BOOST_CHECK(deserializedNetwork);
1779
1780 MeanLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1781 deserializedNetwork->Accept(verifier);
1782}
1783
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001784BOOST_AUTO_TEST_CASE(SerializeMerge)
1785{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001786 DECLARE_LAYER_VERIFIER_CLASS(Merge)
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001787
1788 const std::string layerName("merge");
1789 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1790
1791 armnn::INetworkPtr network = armnn::INetwork::Create();
1792 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1793 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1794 armnn::IConnectableLayer* const mergeLayer = network->AddMergeLayer(layerName.c_str());
1795 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1796
1797 inputLayer0->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(0));
1798 inputLayer1->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(1));
1799 mergeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1800
1801 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1802 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1803 mergeLayer->GetOutputSlot(0).SetTensorInfo(info);
1804
1805 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1806 BOOST_CHECK(deserializedNetwork);
1807
1808 MergeLayerVerifier verifier(layerName, {info, info}, {info});
1809 deserializedNetwork->Accept(verifier);
1810}
1811
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001812class MergerLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001813{
Jim Flynn5fa83932019-05-09 15:35:43 +01001814public:
1815 MergerLayerVerifier(const std::string& layerName,
1816 const std::vector<armnn::TensorInfo>& inputInfos,
1817 const std::vector<armnn::TensorInfo>& outputInfos,
1818 const armnn::OriginsDescriptor& descriptor)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001819 : LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001820
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001821 void VisitMergerLayer(const armnn::IConnectableLayer*,
1822 const armnn::OriginsDescriptor&,
1823 const char*) override
Jim Flynn5fa83932019-05-09 15:35:43 +01001824 {
Jim Flynne242f2d2019-05-22 14:24:13 +01001825 throw armnn::Exception("MergerLayer should have translated to ConcatLayer");
1826 }
1827
1828 void VisitConcatLayer(const armnn::IConnectableLayer* layer,
1829 const armnn::OriginsDescriptor& descriptor,
1830 const char* name) override
1831 {
Jim Flynn5fa83932019-05-09 15:35:43 +01001832 VerifyNameAndConnections(layer, name);
1833 VerifyDescriptor(descriptor);
1834 }
Jim Flynn5fa83932019-05-09 15:35:43 +01001835};
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001836
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001837// NOTE: Until the deprecated AddMergerLayer disappears this test checks that calling
Jim Flynne242f2d2019-05-22 14:24:13 +01001838// AddMergerLayer places a ConcatLayer into the serialized format and that
1839// when this deserialises we have a ConcatLayer
Jim Flynn5fa83932019-05-09 15:35:43 +01001840BOOST_AUTO_TEST_CASE(SerializeMerger)
1841{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001842 const std::string layerName("merger");
1843 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1844 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1845
1846 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1847
1848 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001849 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001850
1851 armnn::INetworkPtr network = armnn::INetwork::Create();
1852 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1853 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
Jim Flynn906f9462019-05-10 13:55:21 +01001854 ARMNN_NO_DEPRECATE_WARN_BEGIN
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001855 armnn::IConnectableLayer* const mergerLayer = network->AddMergerLayer(descriptor, layerName.c_str());
Jim Flynn906f9462019-05-10 13:55:21 +01001856 ARMNN_NO_DEPRECATE_WARN_END
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001857 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1858
1859 inputLayerOne->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0));
1860 inputLayerTwo->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1));
1861 mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1862
1863 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1864 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1865 mergerLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1866
Jim Flynn5fa83932019-05-09 15:35:43 +01001867 std::string mergerLayerNetwork = SerializeNetwork(*network);
1868 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(mergerLayerNetwork);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001869 BOOST_CHECK(deserializedNetwork);
1870
1871 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1872 deserializedNetwork->Accept(verifier);
1873}
1874
Jim Flynn5fa83932019-05-09 15:35:43 +01001875BOOST_AUTO_TEST_CASE(EnsureMergerLayerBackwardCompatibility)
1876{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001877 // The hex data below is a flat buffer containing a simple network with two inputs
Jim Flynne242f2d2019-05-22 14:24:13 +01001878 // a merger layer (now deprecated) and an output layer with dimensions as per the tensor infos below.
1879 //
1880 // This test verifies that we can still read back these old style
Jim Flynn5fa83932019-05-09 15:35:43 +01001881 // models replacing the MergerLayers with ConcatLayers with the same parameters.
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001882 const std::vector<uint8_t> mergerModel =
Jim Flynn5fa83932019-05-09 15:35:43 +01001883 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001884 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1885 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1886 0x38, 0x02, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1888 0xF4, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1889 0x00, 0x00, 0x9A, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1890 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1892 0xF8, 0xFE, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1893 0x00, 0x1F, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1894 0x68, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
1895 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1896 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
1897 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1898 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1899 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1900 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1901 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x72, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1902 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1903 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
1904 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00,
1905 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1906 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1907 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1908 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1909 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1910 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1911 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1912 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1913 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1914 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1915 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1916 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1917 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1918 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1919 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1920 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1921 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1922 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1923 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1924 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1925 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1926 0x02, 0x00, 0x00, 0x00
1927 };
1928
1929 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(mergerModel.begin(), mergerModel.end()));
Jim Flynn5fa83932019-05-09 15:35:43 +01001930 BOOST_CHECK(deserializedNetwork);
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001931
1932 const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 2, 3, 2, 2 }, armnn::DataType::Float32);
1933 const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 4, 3, 2, 2 }, armnn::DataType::Float32);
Jim Flynn5fa83932019-05-09 15:35:43 +01001934
1935 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1936
1937 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001938 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Jim Flynn5fa83932019-05-09 15:35:43 +01001939
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001940 MergerLayerVerifier verifier("merger", { inputInfo, inputInfo }, { outputInfo }, descriptor);
Jim Flynn5fa83932019-05-09 15:35:43 +01001941 deserializedNetwork->Accept(verifier);
1942}
1943
Jim Flynne242f2d2019-05-22 14:24:13 +01001944BOOST_AUTO_TEST_CASE(SerializeConcat)
1945{
1946 const std::string layerName("concat");
1947 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1948 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1949
1950 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1951
1952 armnn::OriginsDescriptor descriptor =
1953 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1954
1955 armnn::INetworkPtr network = armnn::INetwork::Create();
1956 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1957 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1958 armnn::IConnectableLayer* const concatLayer = network->AddConcatLayer(descriptor, layerName.c_str());
1959 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1960
1961 inputLayerOne->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
1962 inputLayerTwo->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
1963 concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1964
1965 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1966 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1967 concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1968
1969 std::string concatLayerNetwork = SerializeNetwork(*network);
1970 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(concatLayerNetwork);
1971 BOOST_CHECK(deserializedNetwork);
1972
1973 // NOTE: using the MergerLayerVerifier to ensure that it is a concat layer and not a
1974 // merger layer that gets placed into the graph.
1975 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1976 deserializedNetwork->Accept(verifier);
1977}
1978
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001979BOOST_AUTO_TEST_CASE(SerializeMinimum)
1980{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001981 DECLARE_LAYER_VERIFIER_CLASS(Minimum)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001982
1983 const std::string layerName("minimum");
1984 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1985
1986 armnn::INetworkPtr network = armnn::INetwork::Create();
1987 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1988 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1989 armnn::IConnectableLayer* const minimumLayer = network->AddMinimumLayer(layerName.c_str());
1990 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1991
1992 inputLayer0->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(0));
1993 inputLayer1->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(1));
1994 minimumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1995
1996 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1997 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1998 minimumLayer->GetOutputSlot(0).SetTensorInfo(info);
1999
2000 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2001 BOOST_CHECK(deserializedNetwork);
2002
2003 MinimumLayerVerifier verifier(layerName, {info, info}, {info});
2004 deserializedNetwork->Accept(verifier);
2005}
2006
2007BOOST_AUTO_TEST_CASE(SerializeMultiplication)
2008{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002009 DECLARE_LAYER_VERIFIER_CLASS(Multiplication)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002010
2011 const std::string layerName("multiplication");
2012 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
2013
2014 armnn::INetworkPtr network = armnn::INetwork::Create();
2015 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2016 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2017 armnn::IConnectableLayer* const multiplicationLayer = network->AddMultiplicationLayer(layerName.c_str());
2018 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2019
2020 inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(0));
2021 inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(1));
2022 multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2023
2024 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2025 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2026 multiplicationLayer->GetOutputSlot(0).SetTensorInfo(info);
2027
2028 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2029 BOOST_CHECK(deserializedNetwork);
2030
2031 MultiplicationLayerVerifier verifier(layerName, {info, info}, {info});
2032 deserializedNetwork->Accept(verifier);
2033}
2034
Ellen Norris-Thompson51982472019-06-19 11:46:21 +01002035BOOST_AUTO_TEST_CASE(SerializePrelu)
2036{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002037 DECLARE_LAYER_VERIFIER_CLASS(Prelu)
Ellen Norris-Thompson51982472019-06-19 11:46:21 +01002038
2039 const std::string layerName("prelu");
2040
2041 armnn::TensorInfo inputTensorInfo ({ 4, 1, 2 }, armnn::DataType::Float32);
2042 armnn::TensorInfo alphaTensorInfo ({ 5, 4, 3, 1 }, armnn::DataType::Float32);
2043 armnn::TensorInfo outputTensorInfo({ 5, 4, 3, 2 }, armnn::DataType::Float32);
2044
2045 armnn::INetworkPtr network = armnn::INetwork::Create();
2046 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2047 armnn::IConnectableLayer* const alphaLayer = network->AddInputLayer(1);
2048 armnn::IConnectableLayer* const preluLayer = network->AddPreluLayer(layerName.c_str());
2049 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2050
2051 inputLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(0));
2052 alphaLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(1));
2053 preluLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2054
2055 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2056 alphaLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2057 preluLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2058
2059 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2060 BOOST_CHECK(deserializedNetwork);
2061
2062 PreluLayerVerifier verifier(layerName, {inputTensorInfo, alphaTensorInfo}, {outputTensorInfo});
2063 deserializedNetwork->Accept(verifier);
2064}
2065
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002066BOOST_AUTO_TEST_CASE(SerializeNormalization)
2067{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002068 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Normalization)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002069
2070 const std::string layerName("normalization");
2071 const armnn::TensorInfo info({2, 1, 2, 2}, armnn::DataType::Float32);
2072
2073 armnn::NormalizationDescriptor desc;
2074 desc.m_DataLayout = armnn::DataLayout::NCHW;
2075 desc.m_NormSize = 3;
2076 desc.m_Alpha = 1;
2077 desc.m_Beta = 1;
2078 desc.m_K = 1;
2079
2080 armnn::INetworkPtr network = armnn::INetwork::Create();
2081 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2082 armnn::IConnectableLayer* const normalizationLayer = network->AddNormalizationLayer(desc, layerName.c_str());
2083 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2084
2085 inputLayer->GetOutputSlot(0).Connect(normalizationLayer->GetInputSlot(0));
2086 normalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2087
2088 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2089 normalizationLayer->GetOutputSlot(0).SetTensorInfo(info);
2090
2091 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2092 BOOST_CHECK(deserializedNetwork);
2093
2094 NormalizationLayerVerifier verifier(layerName, {info}, {info}, desc);
2095 deserializedNetwork->Accept(verifier);
2096}
2097
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002098DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pad)
Jim Flynn965c7c62019-06-24 14:32:41 +01002099
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002100BOOST_AUTO_TEST_CASE(SerializePad)
2101{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002102 const std::string layerName("pad");
2103 const armnn::TensorInfo inputTensorInfo = armnn::TensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2104 const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({1, 3, 5, 7}, armnn::DataType::Float32);
2105
2106 armnn::PadDescriptor desc({{0, 0}, {1, 0}, {1, 1}, {1, 2}});
2107
2108 armnn::INetworkPtr network = armnn::INetwork::Create();
2109 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2110 armnn::IConnectableLayer* const padLayer = network->AddPadLayer(desc, layerName.c_str());
2111 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2112
2113 inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
2114 padLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2115
2116 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2117 padLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2118
2119 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2120 BOOST_CHECK(deserializedNetwork);
2121
2122 PadLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, desc);
2123 deserializedNetwork->Accept(verifier);
2124}
2125
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002126BOOST_AUTO_TEST_CASE(EnsurePadBackwardCompatibility)
Jim Flynn965c7c62019-06-24 14:32:41 +01002127{
2128 // The PadDescriptor is being extended with a float PadValue (so a value other than 0
2129 // can be used to pad the tensor.
2130 //
2131 // This test contains a binary representation of a simple input->pad->output network
2132 // prior to this change to test that the descriptor has been updated in a backward
2133 // compatible way with respect to Deserialization of older binary dumps
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002134 const std::vector<uint8_t> padModel =
Jim Flynn965c7c62019-06-24 14:32:41 +01002135 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002136 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2137 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2138 0x54, 0x01, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2139 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD0, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2140 0x04, 0x00, 0x00, 0x00, 0x96, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
2141 0x00, 0x00, 0x72, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2142 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
2143 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
2144 0x00, 0x00, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x16, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00,
2145 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2146 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00,
2147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2148 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
2149 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
2150 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00,
2151 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
2152 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
2153 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2154 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2155 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
2156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00,
2157 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00,
2158 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2159 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00,
2160 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2162 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2163 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
2164 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
2165 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00
2166 };
2167
2168 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(padModel.begin(), padModel.end()));
Jim Flynn965c7c62019-06-24 14:32:41 +01002169 BOOST_CHECK(deserializedNetwork);
2170
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002171 const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 1, 2, 3, 4 }, armnn::DataType::Float32);
2172 const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 1, 3, 5, 7 }, armnn::DataType::Float32);
Jim Flynn965c7c62019-06-24 14:32:41 +01002173
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002174 armnn::PadDescriptor descriptor({{ 0, 0 }, { 1, 0 }, { 1, 1 }, { 1, 2 }});
Jim Flynn965c7c62019-06-24 14:32:41 +01002175
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002176 PadLayerVerifier verifier("pad", { inputInfo }, { outputInfo }, descriptor);
Jim Flynn965c7c62019-06-24 14:32:41 +01002177 deserializedNetwork->Accept(verifier);
2178}
2179
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002180BOOST_AUTO_TEST_CASE(SerializePermute)
2181{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002182 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Permute)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002183
2184 const std::string layerName("permute");
2185 const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2186 const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2187
2188 armnn::PermuteDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2189
2190 armnn::INetworkPtr network = armnn::INetwork::Create();
2191 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2192 armnn::IConnectableLayer* const permuteLayer = network->AddPermuteLayer(descriptor, layerName.c_str());
2193 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2194
2195 inputLayer->GetOutputSlot(0).Connect(permuteLayer->GetInputSlot(0));
2196 permuteLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2197
2198 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2199 permuteLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2200
2201 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2202 BOOST_CHECK(deserializedNetwork);
2203
2204 PermuteLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2205 deserializedNetwork->Accept(verifier);
2206}
2207
2208BOOST_AUTO_TEST_CASE(SerializePooling2d)
2209{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002210 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pooling2d)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002211
2212 const std::string layerName("pooling2d");
2213 const armnn::TensorInfo inputInfo({1, 2, 2, 1}, armnn::DataType::Float32);
2214 const armnn::TensorInfo outputInfo({1, 1, 1, 1}, armnn::DataType::Float32);
2215
2216 armnn::Pooling2dDescriptor desc;
2217 desc.m_DataLayout = armnn::DataLayout::NHWC;
2218 desc.m_PadTop = 0;
2219 desc.m_PadBottom = 0;
2220 desc.m_PadLeft = 0;
2221 desc.m_PadRight = 0;
2222 desc.m_PoolType = armnn::PoolingAlgorithm::Average;
2223 desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
2224 desc.m_PaddingMethod = armnn::PaddingMethod::Exclude;
2225 desc.m_PoolHeight = 2;
2226 desc.m_PoolWidth = 2;
2227 desc.m_StrideX = 2;
2228 desc.m_StrideY = 2;
2229
2230 armnn::INetworkPtr network = armnn::INetwork::Create();
2231 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2232 armnn::IConnectableLayer* const pooling2dLayer = network->AddPooling2dLayer(desc, layerName.c_str());
2233 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2234
2235 inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0));
2236 pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2237
2238 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2239 pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2240
2241 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2242 BOOST_CHECK(deserializedNetwork);
2243
2244 Pooling2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2245 deserializedNetwork->Accept(verifier);
2246}
2247
Derek Lamberti87acb272019-03-27 16:51:31 +00002248BOOST_AUTO_TEST_CASE(SerializeQuantize)
2249{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002250 DECLARE_LAYER_VERIFIER_CLASS(Quantize)
Derek Lamberti87acb272019-03-27 16:51:31 +00002251
2252 const std::string layerName("quantize");
2253 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
2254
2255 armnn::INetworkPtr network = armnn::INetwork::Create();
2256 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2257 armnn::IConnectableLayer* const quantizeLayer = network->AddQuantizeLayer(layerName.c_str());
2258 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2259
2260 inputLayer->GetOutputSlot(0).Connect(quantizeLayer->GetInputSlot(0));
2261 quantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2262
2263 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2264 quantizeLayer->GetOutputSlot(0).SetTensorInfo(info);
2265
2266 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2267 BOOST_CHECK(deserializedNetwork);
2268
2269 QuantizeLayerVerifier verifier(layerName, {info}, {info});
2270 deserializedNetwork->Accept(verifier);
2271}
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002272
Finn Williams2605b232020-06-10 15:53:46 +01002273BOOST_AUTO_TEST_CASE(SerializeRank)
2274{
2275 DECLARE_LAYER_VERIFIER_CLASS(Rank)
2276
2277 const std::string layerName("rank");
2278 const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2279 const armnn::TensorInfo outputInfo({1}, armnn::DataType::Signed32);
2280
2281 armnn::INetworkPtr network = armnn::INetwork::Create();
2282 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2283 armnn::IConnectableLayer* const rankLayer = network->AddRankLayer(layerName.c_str());
2284 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2285
2286 inputLayer->GetOutputSlot(0).Connect(rankLayer->GetInputSlot(0));
2287 rankLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2288
2289 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2290 rankLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2291
2292 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2293 BOOST_CHECK(deserializedNetwork);
2294
2295 RankLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
2296 deserializedNetwork->Accept(verifier);
2297}
2298
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002299BOOST_AUTO_TEST_CASE(SerializeReshape)
2300{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002301 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Reshape)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002302
2303 const std::string layerName("reshape");
2304 const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2305 const armnn::TensorInfo outputInfo({3, 3}, armnn::DataType::Float32);
2306
2307 armnn::ReshapeDescriptor descriptor({3, 3});
2308
2309 armnn::INetworkPtr network = armnn::INetwork::Create();
2310 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2311 armnn::IConnectableLayer* const reshapeLayer = network->AddReshapeLayer(descriptor, layerName.c_str());
2312 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2313
2314 inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0));
2315 reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2316
2317 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2318 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2319
2320 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2321 BOOST_CHECK(deserializedNetwork);
2322
2323 ReshapeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2324 deserializedNetwork->Accept(verifier);
2325}
2326
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002327BOOST_AUTO_TEST_CASE(SerializeResize)
2328{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002329 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Resize)
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002330
2331 const std::string layerName("resize");
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002332 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002333 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2334
2335 armnn::ResizeDescriptor desc;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002336 desc.m_TargetWidth = 4;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002337 desc.m_TargetHeight = 2;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002338 desc.m_Method = armnn::ResizeMethod::NearestNeighbor;
David Monahan4a0c9b92020-05-30 09:48:39 +01002339 desc.m_AlignCorners = true;
2340 desc.m_HalfPixelCenters = true;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002341
2342 armnn::INetworkPtr network = armnn::INetwork::Create();
2343 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2344 armnn::IConnectableLayer* const resizeLayer = network->AddResizeLayer(desc, layerName.c_str());
2345 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2346
2347 inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2348 resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2349
2350 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2351 resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2352
2353 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2354 BOOST_CHECK(deserializedNetwork);
2355
2356 ResizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2357 deserializedNetwork->Accept(verifier);
2358}
2359
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002360class ResizeBilinearLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>
2361{
2362public:
2363 ResizeBilinearLayerVerifier(const std::string& layerName,
2364 const std::vector<armnn::TensorInfo>& inputInfos,
2365 const std::vector<armnn::TensorInfo>& outputInfos,
2366 const armnn::ResizeBilinearDescriptor& descriptor)
2367 : LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>(
2368 layerName, inputInfos, outputInfos, descriptor) {}
2369
2370 void VisitResizeLayer(const armnn::IConnectableLayer* layer,
2371 const armnn::ResizeDescriptor& descriptor,
2372 const char* name) override
2373 {
2374 VerifyNameAndConnections(layer, name);
2375
David Monahan4a0c9b92020-05-30 09:48:39 +01002376 BOOST_CHECK(descriptor.m_Method == armnn::ResizeMethod::Bilinear);
2377 BOOST_CHECK(descriptor.m_TargetWidth == m_Descriptor.m_TargetWidth);
2378 BOOST_CHECK(descriptor.m_TargetHeight == m_Descriptor.m_TargetHeight);
2379 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
2380 BOOST_CHECK(descriptor.m_AlignCorners == m_Descriptor.m_AlignCorners);
2381 BOOST_CHECK(descriptor.m_HalfPixelCenters == m_Descriptor.m_HalfPixelCenters);
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002382 }
2383
2384 void VisitResizeBilinearLayer(const armnn::IConnectableLayer*,
2385 const armnn::ResizeBilinearDescriptor&,
2386 const char*) override
2387 {
2388 throw armnn::Exception("ResizeBilinearLayer should have translated to ResizeLayer");
2389 }
2390};
2391
2392// NOTE: Until the deprecated AddResizeBilinearLayer disappears this test checks that
2393// calling AddResizeBilinearLayer places a ResizeLayer into the serialized format
2394// and that when this deserialises we have a ResizeLayer
2395BOOST_AUTO_TEST_CASE(SerializeResizeBilinear)
2396{
2397 const std::string layerName("resizeBilinear");
2398 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2399 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2400
2401 armnn::ResizeBilinearDescriptor desc;
2402 desc.m_TargetWidth = 4u;
2403 desc.m_TargetHeight = 2u;
David Monahan4a0c9b92020-05-30 09:48:39 +01002404 desc.m_AlignCorners = true;
2405 desc.m_HalfPixelCenters = true;
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002406
2407 armnn::INetworkPtr network = armnn::INetwork::Create();
2408 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2409 ARMNN_NO_DEPRECATE_WARN_BEGIN
2410 armnn::IConnectableLayer* const resizeLayer = network->AddResizeBilinearLayer(desc, layerName.c_str());
2411 ARMNN_NO_DEPRECATE_WARN_END
2412 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2413
2414 inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2415 resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2416
2417 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2418 resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2419
2420 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2421 BOOST_CHECK(deserializedNetwork);
2422
2423 ResizeBilinearLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2424 deserializedNetwork->Accept(verifier);
2425}
2426
2427BOOST_AUTO_TEST_CASE(EnsureResizeBilinearBackwardCompatibility)
2428{
2429 // The hex data below is a flat buffer containing a simple network with an input,
2430 // a ResizeBilinearLayer (now deprecated) and an output
2431 //
2432 // This test verifies that we can still deserialize this old-style model by replacing
2433 // the ResizeBilinearLayer with an equivalent ResizeLayer
2434 const std::vector<uint8_t> resizeBilinearModel =
2435 {
2436 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2437 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2438 0x50, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2439 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD4, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2440 0x04, 0x00, 0x00, 0x00, 0xC2, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
2441 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8A, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
2442 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2444 0x38, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
2445 0x00, 0x1A, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
2446 0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x08, 0x00, 0x0C, 0x00,
2447 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
2448 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00,
2449 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
2450 0x20, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x42, 0x69, 0x6C, 0x69,
2451 0x6E, 0x65, 0x61, 0x72, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2452 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
2453 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2454 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
2455 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2456 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
2457 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
2458 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00,
2459 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
2460 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00,
2462 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00,
2463 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2464 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2465 0x00, 0x00, 0x05, 0x00, 0x00, 0x00
2466 };
2467
2468 armnn::INetworkPtr deserializedNetwork =
2469 DeserializeNetwork(std::string(resizeBilinearModel.begin(), resizeBilinearModel.end()));
2470 BOOST_CHECK(deserializedNetwork);
2471
2472 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2473 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2474
2475 armnn::ResizeBilinearDescriptor descriptor;
2476 descriptor.m_TargetWidth = 4u;
2477 descriptor.m_TargetHeight = 2u;
2478
2479 ResizeBilinearLayerVerifier verifier("resizeBilinear", { inputInfo }, { outputInfo }, descriptor);
2480 deserializedNetwork->Accept(verifier);
2481}
2482
Aron Virginas-Tar2fda80b2019-09-18 13:36:52 +01002483BOOST_AUTO_TEST_CASE(SerializeSlice)
2484{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002485 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Slice)
Aron Virginas-Tar2fda80b2019-09-18 13:36:52 +01002486
2487 const std::string layerName{"slice"};
2488
2489 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2490 const armnn::TensorInfo outputInfo = armnn::TensorInfo({2, 2, 2, 1}, armnn::DataType::Float32);
2491
2492 armnn::SliceDescriptor descriptor({ 0, 0, 1, 0}, {2, 2, 2, 1});
2493
2494 armnn::INetworkPtr network = armnn::INetwork::Create();
2495
2496 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2497 armnn::IConnectableLayer* const sliceLayer = network->AddSliceLayer(descriptor, layerName.c_str());
2498 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2499
2500 inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
2501 sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2502
2503 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2504 sliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2505
2506 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2507 BOOST_CHECK(deserializedNetwork);
2508
2509 SliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2510 deserializedNetwork->Accept(verifier);
2511}
2512
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002513BOOST_AUTO_TEST_CASE(SerializeSoftmax)
2514{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002515 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Softmax)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002516
2517 const std::string layerName("softmax");
2518 const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
2519
2520 armnn::SoftmaxDescriptor descriptor;
2521 descriptor.m_Beta = 1.0f;
2522
2523 armnn::INetworkPtr network = armnn::INetwork::Create();
2524 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2525 armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, layerName.c_str());
2526 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2527
2528 inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
2529 softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2530
2531 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2532 softmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
2533
2534 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2535 BOOST_CHECK(deserializedNetwork);
2536
2537 SoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
2538 deserializedNetwork->Accept(verifier);
2539}
2540
2541BOOST_AUTO_TEST_CASE(SerializeSpaceToBatchNd)
2542{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002543 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToBatchNd)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002544
2545 const std::string layerName("spaceToBatchNd");
2546 const armnn::TensorInfo inputInfo({2, 1, 2, 4}, armnn::DataType::Float32);
2547 const armnn::TensorInfo outputInfo({8, 1, 1, 3}, armnn::DataType::Float32);
2548
2549 armnn::SpaceToBatchNdDescriptor desc;
2550 desc.m_DataLayout = armnn::DataLayout::NCHW;
2551 desc.m_BlockShape = {2, 2};
2552 desc.m_PadList = {{0, 0}, {2, 0}};
2553
2554 armnn::INetworkPtr network = armnn::INetwork::Create();
2555 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2556 armnn::IConnectableLayer* const spaceToBatchNdLayer = network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2557 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2558
2559 inputLayer->GetOutputSlot(0).Connect(spaceToBatchNdLayer->GetInputSlot(0));
2560 spaceToBatchNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2561
2562 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2563 spaceToBatchNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2564
2565 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2566 BOOST_CHECK(deserializedNetwork);
2567
2568 SpaceToBatchNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2569 deserializedNetwork->Accept(verifier);
2570}
2571
Aron Virginas-Taraa067142019-06-11 16:01:44 +01002572BOOST_AUTO_TEST_CASE(SerializeSpaceToDepth)
2573{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002574 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToDepth)
Aron Virginas-Taraa067142019-06-11 16:01:44 +01002575
2576 const std::string layerName("spaceToDepth");
2577
2578 const armnn::TensorInfo inputInfo ({ 1, 16, 8, 3 }, armnn::DataType::Float32);
2579 const armnn::TensorInfo outputInfo({ 1, 8, 4, 12 }, armnn::DataType::Float32);
2580
2581 armnn::SpaceToDepthDescriptor desc;
2582 desc.m_BlockSize = 2;
2583 desc.m_DataLayout = armnn::DataLayout::NHWC;
2584
2585 armnn::INetworkPtr network = armnn::INetwork::Create();
2586 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2587 armnn::IConnectableLayer* const spaceToDepthLayer = network->AddSpaceToDepthLayer(desc, layerName.c_str());
2588 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2589
2590 inputLayer->GetOutputSlot(0).Connect(spaceToDepthLayer->GetInputSlot(0));
2591 spaceToDepthLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2592
2593 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2594 spaceToDepthLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2595
2596 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2597 BOOST_CHECK(deserializedNetwork);
2598
2599 SpaceToDepthLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2600 deserializedNetwork->Accept(verifier);
2601}
2602
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002603BOOST_AUTO_TEST_CASE(SerializeSplitter)
2604{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002605 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Splitter)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002606
2607 const unsigned int numViews = 3;
2608 const unsigned int numDimensions = 4;
2609 const unsigned int inputShape[] = {1, 18, 4, 4};
2610 const unsigned int outputShape[] = {1, 6, 4, 4};
2611
2612 // This is modelled on how the caffe parser sets up a splitter layer to partition an input along dimension one.
2613 unsigned int splitterDimSizes[4] = {static_cast<unsigned int>(inputShape[0]),
2614 static_cast<unsigned int>(inputShape[1]),
2615 static_cast<unsigned int>(inputShape[2]),
2616 static_cast<unsigned int>(inputShape[3])};
2617 splitterDimSizes[1] /= numViews;
2618 armnn::ViewsDescriptor desc(numViews, numDimensions);
2619
2620 for (unsigned int g = 0; g < numViews; ++g)
2621 {
2622 desc.SetViewOriginCoord(g, 1, splitterDimSizes[1] * g);
2623
2624 for (unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
2625 {
2626 desc.SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
2627 }
2628 }
2629
2630 const std::string layerName("splitter");
2631 const armnn::TensorInfo inputInfo(numDimensions, inputShape, armnn::DataType::Float32);
2632 const armnn::TensorInfo outputInfo(numDimensions, outputShape, armnn::DataType::Float32);
2633
2634 armnn::INetworkPtr network = armnn::INetwork::Create();
2635 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2636 armnn::IConnectableLayer* const splitterLayer = network->AddSplitterLayer(desc, layerName.c_str());
2637 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2638 armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2639 armnn::IConnectableLayer* const outputLayer2 = network->AddOutputLayer(2);
2640
2641 inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
2642 splitterLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2643 splitterLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2644 splitterLayer->GetOutputSlot(2).Connect(outputLayer2->GetInputSlot(0));
2645
2646 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2647 splitterLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2648 splitterLayer->GetOutputSlot(1).SetTensorInfo(outputInfo);
2649 splitterLayer->GetOutputSlot(2).SetTensorInfo(outputInfo);
2650
2651 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2652 BOOST_CHECK(deserializedNetwork);
2653
2654 SplitterLayerVerifier verifier(layerName, {inputInfo}, {outputInfo, outputInfo, outputInfo}, desc);
2655 deserializedNetwork->Accept(verifier);
2656}
2657
Matthew Jacksonb5433ee2019-07-11 15:54:20 +01002658BOOST_AUTO_TEST_CASE(SerializeStack)
2659{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002660 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Stack)
Matthew Jacksonb5433ee2019-07-11 15:54:20 +01002661
2662 const std::string layerName("stack");
2663
2664 armnn::TensorInfo inputTensorInfo ({4, 3, 5}, armnn::DataType::Float32);
2665 armnn::TensorInfo outputTensorInfo({4, 3, 2, 5}, armnn::DataType::Float32);
2666
2667 armnn::StackDescriptor descriptor(2, 2, {4, 3, 5});
2668
2669 armnn::INetworkPtr network = armnn::INetwork::Create();
2670 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
2671 armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
2672 armnn::IConnectableLayer* const stackLayer = network->AddStackLayer(descriptor, layerName.c_str());
2673 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2674
2675 inputLayer1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
2676 inputLayer2->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
2677 stackLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2678
2679 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2680 inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2681 stackLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2682
2683 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2684 BOOST_CHECK(deserializedNetwork);
2685
2686 StackLayerVerifier verifier(layerName, {inputTensorInfo, inputTensorInfo}, {outputTensorInfo}, descriptor);
2687 deserializedNetwork->Accept(verifier);
2688}
2689
Aron Virginas-Tar85121a22019-10-23 10:41:35 +01002690BOOST_AUTO_TEST_CASE(SerializeStandIn)
2691{
2692 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StandIn)
2693
2694 const std::string layerName("standIn");
2695
2696 armnn::TensorInfo tensorInfo({ 1u }, armnn::DataType::Float32);
2697 armnn::StandInDescriptor descriptor(2u, 2u);
2698
2699 armnn::INetworkPtr network = armnn::INetwork::Create();
2700 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2701 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2702 armnn::IConnectableLayer* const standInLayer = network->AddStandInLayer(descriptor, layerName.c_str());
2703 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2704 armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2705
2706 inputLayer0->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(0));
2707 inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2708
2709 inputLayer1->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(1));
2710 inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2711
2712 standInLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2713 standInLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2714
2715 standInLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2716 standInLayer->GetOutputSlot(1).SetTensorInfo(tensorInfo);
2717
2718 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2719 BOOST_CHECK(deserializedNetwork);
2720
2721 StandInLayerVerifier verifier(layerName, { tensorInfo, tensorInfo }, { tensorInfo, tensorInfo }, descriptor);
2722 deserializedNetwork->Accept(verifier);
2723}
2724
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002725BOOST_AUTO_TEST_CASE(SerializeStridedSlice)
2726{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002727 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StridedSlice)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002728
2729 const std::string layerName("stridedSlice");
2730 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2731 const armnn::TensorInfo outputInfo = armnn::TensorInfo({3, 1}, armnn::DataType::Float32);
2732
2733 armnn::StridedSliceDescriptor desc({0, 0, 1, 0}, {1, 1, 1, 1}, {1, 1, 1, 1});
2734 desc.m_EndMask = (1 << 4) - 1;
2735 desc.m_ShrinkAxisMask = (1 << 1) | (1 << 2);
2736 desc.m_DataLayout = armnn::DataLayout::NCHW;
2737
2738 armnn::INetworkPtr network = armnn::INetwork::Create();
2739 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2740 armnn::IConnectableLayer* const stridedSliceLayer = network->AddStridedSliceLayer(desc, layerName.c_str());
2741 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2742
2743 inputLayer->GetOutputSlot(0).Connect(stridedSliceLayer->GetInputSlot(0));
2744 stridedSliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2745
2746 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2747 stridedSliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2748
2749 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2750 BOOST_CHECK(deserializedNetwork);
2751
2752 StridedSliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2753 deserializedNetwork->Accept(verifier);
2754}
2755
2756BOOST_AUTO_TEST_CASE(SerializeSubtraction)
2757{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002758 DECLARE_LAYER_VERIFIER_CLASS(Subtraction)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002759
2760 const std::string layerName("subtraction");
2761 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2762
2763 armnn::INetworkPtr network = armnn::INetwork::Create();
2764 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2765 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2766 armnn::IConnectableLayer* const subtractionLayer = network->AddSubtractionLayer(layerName.c_str());
2767 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2768
2769 inputLayer0->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(0));
2770 inputLayer1->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(1));
2771 subtractionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2772
2773 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2774 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2775 subtractionLayer->GetOutputSlot(0).SetTensorInfo(info);
2776
2777 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2778 BOOST_CHECK(deserializedNetwork);
2779
2780 SubtractionLayerVerifier verifier(layerName, {info, info}, {info});
2781 deserializedNetwork->Accept(verifier);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00002782}
2783
Sadik Armaganeff363d2019-04-05 15:25:46 +01002784BOOST_AUTO_TEST_CASE(SerializeSwitch)
2785{
2786 class SwitchLayerVerifier : public LayerVerifierBase
2787 {
2788 public:
2789 SwitchLayerVerifier(const std::string& layerName,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002790 const std::vector<armnn::TensorInfo>& inputInfos,
2791 const std::vector<armnn::TensorInfo>& outputInfos)
Sadik Armaganeff363d2019-04-05 15:25:46 +01002792 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2793
2794 void VisitSwitchLayer(const armnn::IConnectableLayer* layer, const char* name) override
2795 {
2796 VerifyNameAndConnections(layer, name);
2797 }
2798
Derek Lamberti859f9ce2019-12-10 22:05:21 +00002799 void VisitConstantLayer(const armnn::IConnectableLayer*,
2800 const armnn::ConstTensor&,
2801 const char*) override {}
Sadik Armaganeff363d2019-04-05 15:25:46 +01002802 };
2803
2804 const std::string layerName("switch");
2805 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2806
2807 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2808 armnn::ConstTensor constTensor(info, constantData);
2809
2810 armnn::INetworkPtr network = armnn::INetwork::Create();
2811 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2812 armnn::IConnectableLayer* const constantLayer = network->AddConstantLayer(constTensor, "constant");
2813 armnn::IConnectableLayer* const switchLayer = network->AddSwitchLayer(layerName.c_str());
2814 armnn::IConnectableLayer* const trueOutputLayer = network->AddOutputLayer(0);
2815 armnn::IConnectableLayer* const falseOutputLayer = network->AddOutputLayer(1);
2816
2817 inputLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(0));
2818 constantLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(1));
2819 switchLayer->GetOutputSlot(0).Connect(trueOutputLayer->GetInputSlot(0));
2820 switchLayer->GetOutputSlot(1).Connect(falseOutputLayer->GetInputSlot(0));
2821
2822 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2823 constantLayer->GetOutputSlot(0).SetTensorInfo(info);
2824 switchLayer->GetOutputSlot(0).SetTensorInfo(info);
2825 switchLayer->GetOutputSlot(1).SetTensorInfo(info);
2826
2827 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2828 BOOST_CHECK(deserializedNetwork);
2829
2830 SwitchLayerVerifier verifier(layerName, {info, info}, {info, info});
2831 deserializedNetwork->Accept(verifier);
2832}
2833
Mike Kellyc9ea45a2020-02-28 18:11:58 +00002834BOOST_AUTO_TEST_CASE(SerializeTranspose)
2835{
2836 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Transpose)
2837
2838 const std::string layerName("transpose");
2839 const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2840 const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2841
2842 armnn::TransposeDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2843
2844 armnn::INetworkPtr network = armnn::INetwork::Create();
2845 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2846 armnn::IConnectableLayer* const transposeLayer = network->AddTransposeLayer(descriptor, layerName.c_str());
2847 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2848
2849 inputLayer->GetOutputSlot(0).Connect(transposeLayer->GetInputSlot(0));
2850 transposeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2851
2852 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2853 transposeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2854
2855 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2856 BOOST_CHECK(deserializedNetwork);
2857
2858 TransposeLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2859 deserializedNetwork->Accept(verifier);
2860}
2861
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002862BOOST_AUTO_TEST_CASE(SerializeTransposeConvolution2d)
2863{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002864 using Descriptor = armnn::TransposeConvolution2dDescriptor;
2865 class TransposeConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002866 {
2867 public:
2868 TransposeConvolution2dLayerVerifier(const std::string& layerName,
2869 const std::vector<armnn::TensorInfo>& inputInfos,
2870 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002871 const Descriptor& descriptor,
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002872 const armnn::ConstTensor& weights,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002873 const armnn::Optional<armnn::ConstTensor>& biases)
2874 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
2875 , m_Weights(weights)
2876 , m_Biases(biases)
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002877 {}
2878
2879 void VisitTransposeConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002880 const Descriptor& descriptor,
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002881 const armnn::ConstTensor& weights,
2882 const armnn::Optional<armnn::ConstTensor>& biases,
2883 const char* name) override
2884 {
2885 VerifyNameAndConnections(layer, name);
2886 VerifyDescriptor(descriptor);
2887
2888 // check weights
2889 CompareConstTensor(weights, m_Weights);
2890
2891 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002892 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002893 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
2894
2895 if (biases.has_value() && m_Biases.has_value())
2896 {
2897 CompareConstTensor(biases.value(), m_Biases.value());
2898 }
2899 }
2900
2901 private:
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002902 armnn::ConstTensor m_Weights;
2903 armnn::Optional<armnn::ConstTensor> m_Biases;
2904 };
2905
2906 const std::string layerName("transposeConvolution2d");
2907 const armnn::TensorInfo inputInfo ({ 1, 7, 7, 1 }, armnn::DataType::Float32);
2908 const armnn::TensorInfo outputInfo({ 1, 9, 9, 1 }, armnn::DataType::Float32);
2909
2910 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
2911 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
2912
2913 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
2914 armnn::ConstTensor weights(weightsInfo, weightsData);
2915
2916 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
2917 armnn::ConstTensor biases(biasesInfo, biasesData);
2918
2919 armnn::TransposeConvolution2dDescriptor descriptor;
2920 descriptor.m_PadLeft = 1;
2921 descriptor.m_PadRight = 1;
2922 descriptor.m_PadTop = 1;
2923 descriptor.m_PadBottom = 1;
2924 descriptor.m_StrideX = 1;
2925 descriptor.m_StrideY = 1;
2926 descriptor.m_BiasEnabled = true;
2927 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
2928
2929 armnn::INetworkPtr network = armnn::INetwork::Create();
2930 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2931 armnn::IConnectableLayer* const convLayer =
2932 network->AddTransposeConvolution2dLayer(descriptor,
2933 weights,
2934 armnn::Optional<armnn::ConstTensor>(biases),
2935 layerName.c_str());
2936 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2937
2938 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
2939 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2940
2941 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2942 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2943
2944 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2945 BOOST_CHECK(deserializedNetwork);
2946
2947 TransposeConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
2948 deserializedNetwork->Accept(verifier);
2949}
2950
Sadik Armagandb059fd2019-03-20 12:28:32 +00002951BOOST_AUTO_TEST_CASE(SerializeDeserializeNonLinearNetwork)
2952{
2953 class ConstantLayerVerifier : public LayerVerifierBase
2954 {
2955 public:
2956 ConstantLayerVerifier(const std::string& layerName,
2957 const std::vector<armnn::TensorInfo>& inputInfos,
2958 const std::vector<armnn::TensorInfo>& outputInfos,
2959 const armnn::ConstTensor& layerInput)
2960 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2961 , m_LayerInput(layerInput) {}
2962
2963 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
2964 const armnn::ConstTensor& input,
2965 const char* name) override
2966 {
2967 VerifyNameAndConnections(layer, name);
Sadik Armagandb059fd2019-03-20 12:28:32 +00002968 CompareConstTensor(input, m_LayerInput);
2969 }
2970
Derek Lamberti859f9ce2019-12-10 22:05:21 +00002971 void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
Sadik Armagandb059fd2019-03-20 12:28:32 +00002972
2973 private:
2974 armnn::ConstTensor m_LayerInput;
2975 };
2976
2977 const std::string layerName("constant");
2978 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
2979
2980 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2981 armnn::ConstTensor constTensor(info, constantData);
2982
2983 armnn::INetworkPtr network(armnn::INetwork::Create());
2984 armnn::IConnectableLayer* input = network->AddInputLayer(0);
2985 armnn::IConnectableLayer* add = network->AddAdditionLayer();
2986 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
2987 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
2988
2989 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
2990 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
2991 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2992
2993 input->GetOutputSlot(0).SetTensorInfo(info);
2994 constant->GetOutputSlot(0).SetTensorInfo(info);
2995 add->GetOutputSlot(0).SetTensorInfo(info);
2996
2997 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2998 BOOST_CHECK(deserializedNetwork);
2999
3000 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
3001 deserializedNetwork->Accept(verifier);
3002}
3003
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003004class VerifyLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>
Jim Flynn11af3752019-03-19 17:22:29 +00003005{
3006public:
3007 VerifyLstmLayer(const std::string& layerName,
3008 const std::vector<armnn::TensorInfo>& inputInfos,
3009 const std::vector<armnn::TensorInfo>& outputInfos,
3010 const armnn::LstmDescriptor& descriptor,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003011 const armnn::LstmInputParams& inputParams)
3012 : LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
3013 , m_InputParams(inputParams) {}
3014
Jim Flynn11af3752019-03-19 17:22:29 +00003015 void VisitLstmLayer(const armnn::IConnectableLayer* layer,
3016 const armnn::LstmDescriptor& descriptor,
3017 const armnn::LstmInputParams& params,
3018 const char* name)
3019 {
3020 VerifyNameAndConnections(layer, name);
3021 VerifyDescriptor(descriptor);
3022 VerifyInputParameters(params);
3023 }
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003024
Jim Flynn11af3752019-03-19 17:22:29 +00003025protected:
Jim Flynn11af3752019-03-19 17:22:29 +00003026 void VerifyInputParameters(const armnn::LstmInputParams& params)
3027 {
3028 VerifyConstTensors(
3029 "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
3030 VerifyConstTensors(
3031 "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
3032 VerifyConstTensors(
3033 "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
3034 VerifyConstTensors(
3035 "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
3036 VerifyConstTensors(
3037 "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
3038 VerifyConstTensors(
3039 "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
3040 VerifyConstTensors(
3041 "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
3042 VerifyConstTensors(
3043 "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
3044 VerifyConstTensors(
3045 "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
3046 VerifyConstTensors(
3047 "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
3048 VerifyConstTensors(
3049 "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
3050 VerifyConstTensors(
3051 "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
3052 VerifyConstTensors(
3053 "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
3054 VerifyConstTensors(
3055 "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
3056 VerifyConstTensors(
3057 "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
3058 VerifyConstTensors(
3059 "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
3060 VerifyConstTensors(
3061 "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
Jan Eilersf8c62972019-07-17 11:07:49 +01003062 VerifyConstTensors(
3063 "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
3064 VerifyConstTensors(
3065 "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
3066 VerifyConstTensors(
3067 "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
3068 VerifyConstTensors(
3069 "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
Jim Flynn11af3752019-03-19 17:22:29 +00003070 }
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003071
Jim Flynn11af3752019-03-19 17:22:29 +00003072private:
Jim Flynn11af3752019-03-19 17:22:29 +00003073 armnn::LstmInputParams m_InputParams;
3074};
3075
3076BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmCifgPeepholeNoProjection)
3077{
3078 armnn::LstmDescriptor descriptor;
3079 descriptor.m_ActivationFunc = 4;
3080 descriptor.m_ClippingThresProj = 0.0f;
3081 descriptor.m_ClippingThresCell = 0.0f;
3082 descriptor.m_CifgEnabled = true; // if this is true then we DON'T need to set the OptCifgParams
3083 descriptor.m_ProjectionEnabled = false;
3084 descriptor.m_PeepholeEnabled = true;
3085
3086 const uint32_t batchSize = 1;
3087 const uint32_t inputSize = 2;
3088 const uint32_t numUnits = 4;
3089 const uint32_t outputSize = numUnits;
3090
3091 armnn::TensorInfo inputWeightsInfo1({numUnits, inputSize}, armnn::DataType::Float32);
3092 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3093 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo1, inputToForgetWeightsData);
3094
3095 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3096 armnn::ConstTensor inputToCellWeights(inputWeightsInfo1, inputToCellWeightsData);
3097
3098 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3099 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo1, inputToOutputWeightsData);
3100
3101 armnn::TensorInfo inputWeightsInfo2({numUnits, outputSize}, armnn::DataType::Float32);
3102 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3103 armnn::ConstTensor recurrentToForgetWeights(inputWeightsInfo2, recurrentToForgetWeightsData);
3104
3105 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3106 armnn::ConstTensor recurrentToCellWeights(inputWeightsInfo2, recurrentToCellWeightsData);
3107
3108 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3109 armnn::ConstTensor recurrentToOutputWeights(inputWeightsInfo2, recurrentToOutputWeightsData);
3110
3111 armnn::TensorInfo inputWeightsInfo3({numUnits}, armnn::DataType::Float32);
3112 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3113 armnn::ConstTensor cellToForgetWeights(inputWeightsInfo3, cellToForgetWeightsData);
3114
3115 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3116 armnn::ConstTensor cellToOutputWeights(inputWeightsInfo3, cellToOutputWeightsData);
3117
3118 std::vector<float> forgetGateBiasData(numUnits, 1.0f);
3119 armnn::ConstTensor forgetGateBias(inputWeightsInfo3, forgetGateBiasData);
3120
3121 std::vector<float> cellBiasData(numUnits, 0.0f);
3122 armnn::ConstTensor cellBias(inputWeightsInfo3, cellBiasData);
3123
3124 std::vector<float> outputGateBiasData(numUnits, 0.0f);
3125 armnn::ConstTensor outputGateBias(inputWeightsInfo3, outputGateBiasData);
3126
3127 armnn::LstmInputParams params;
3128 params.m_InputToForgetWeights = &inputToForgetWeights;
3129 params.m_InputToCellWeights = &inputToCellWeights;
3130 params.m_InputToOutputWeights = &inputToOutputWeights;
3131 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3132 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3133 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3134 params.m_ForgetGateBias = &forgetGateBias;
3135 params.m_CellBias = &cellBias;
3136 params.m_OutputGateBias = &outputGateBias;
3137 params.m_CellToForgetWeights = &cellToForgetWeights;
3138 params.m_CellToOutputWeights = &cellToOutputWeights;
3139
3140 armnn::INetworkPtr network = armnn::INetwork::Create();
3141 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3142 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3143 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3144 const std::string layerName("lstm");
3145 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3146 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3147 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3148 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3149 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3150
3151 // connect up
3152 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3153 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3154 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3155 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 3 }, armnn::DataType::Float32);
3156
3157 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3158 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3159
3160 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3161 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3162
3163 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3164 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3165
3166 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3167 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3168
3169 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3170 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3171
3172 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3173 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3174
3175 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3176 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3177
3178 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3179 BOOST_CHECK(deserializedNetwork);
3180
3181 VerifyLstmLayer checker(
3182 layerName,
3183 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3184 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3185 descriptor,
3186 params);
3187 deserializedNetwork->Accept(checker);
3188}
3189
3190BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeAndProjection)
3191{
3192 armnn::LstmDescriptor descriptor;
3193 descriptor.m_ActivationFunc = 4;
3194 descriptor.m_ClippingThresProj = 0.0f;
3195 descriptor.m_ClippingThresCell = 0.0f;
3196 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3197 descriptor.m_ProjectionEnabled = true;
3198 descriptor.m_PeepholeEnabled = true;
3199
3200 const uint32_t batchSize = 2;
3201 const uint32_t inputSize = 5;
3202 const uint32_t numUnits = 20;
3203 const uint32_t outputSize = 16;
3204
3205 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3206 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3207 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3208
3209 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3210 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3211
3212 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3213 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3214
3215 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3216 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3217
3218 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3219 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3220 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3221
3222 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3223 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3224
3225 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3226 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3227
3228 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3229 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3230
3231 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3232 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3233 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3234
3235 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3236 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3237
3238 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3239 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3240
3241 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3242 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3243
3244 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3245 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3246
3247 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3248 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3249
3250 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3251 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3252
3253 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3254 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3255 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3256
3257 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3258 std::vector<float> projectionBiasData(outputSize, 0.f);
3259 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3260
3261 armnn::LstmInputParams params;
3262 params.m_InputToForgetWeights = &inputToForgetWeights;
3263 params.m_InputToCellWeights = &inputToCellWeights;
3264 params.m_InputToOutputWeights = &inputToOutputWeights;
3265 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3266 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3267 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3268 params.m_ForgetGateBias = &forgetGateBias;
3269 params.m_CellBias = &cellBias;
3270 params.m_OutputGateBias = &outputGateBias;
3271
3272 // additional params because: descriptor.m_CifgEnabled = false
3273 params.m_InputToInputWeights = &inputToInputWeights;
3274 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3275 params.m_CellToInputWeights = &cellToInputWeights;
3276 params.m_InputGateBias = &inputGateBias;
3277
3278 // additional params because: descriptor.m_ProjectionEnabled = true
3279 params.m_ProjectionWeights = &projectionWeights;
3280 params.m_ProjectionBias = &projectionBias;
3281
3282 // additional params because: descriptor.m_PeepholeEnabled = true
3283 params.m_CellToForgetWeights = &cellToForgetWeights;
3284 params.m_CellToOutputWeights = &cellToOutputWeights;
3285
3286 armnn::INetworkPtr network = armnn::INetwork::Create();
3287 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3288 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3289 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3290 const std::string layerName("lstm");
3291 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3292 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3293 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3294 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3295 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3296
3297 // connect up
3298 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3299 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3300 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3301 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3302
3303 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3304 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3305
3306 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3307 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3308
3309 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3310 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3311
3312 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3313 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3314
3315 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3316 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3317
3318 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3319 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3320
3321 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3322 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3323
3324 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3325 BOOST_CHECK(deserializedNetwork);
3326
3327 VerifyLstmLayer checker(
3328 layerName,
3329 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3330 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3331 descriptor,
3332 params);
3333 deserializedNetwork->Accept(checker);
3334}
3335
Jan Eilersf8c62972019-07-17 11:07:49 +01003336BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeWithProjectionWithLayerNorm)
3337{
3338 armnn::LstmDescriptor descriptor;
3339 descriptor.m_ActivationFunc = 4;
3340 descriptor.m_ClippingThresProj = 0.0f;
3341 descriptor.m_ClippingThresCell = 0.0f;
3342 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3343 descriptor.m_ProjectionEnabled = true;
3344 descriptor.m_PeepholeEnabled = true;
3345 descriptor.m_LayerNormEnabled = true;
3346
3347 const uint32_t batchSize = 2;
3348 const uint32_t inputSize = 5;
3349 const uint32_t numUnits = 20;
3350 const uint32_t outputSize = 16;
3351
3352 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3353 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3354 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3355
3356 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3357 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3358
3359 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3360 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3361
3362 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3363 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3364
3365 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3366 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3367 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3368
3369 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3370 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3371
3372 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3373 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3374
3375 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3376 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3377
3378 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3379 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3380 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3381
3382 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3383 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3384
3385 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3386 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3387
3388 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3389 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3390
3391 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3392 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3393
3394 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3395 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3396
3397 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3398 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3399
3400 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3401 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3402 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3403
3404 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3405 std::vector<float> projectionBiasData(outputSize, 0.f);
3406 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3407
3408 std::vector<float> inputLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3409 armnn::ConstTensor inputLayerNormWeights(tensorInfo20, forgetGateBiasData);
3410
3411 std::vector<float> forgetLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3412 armnn::ConstTensor forgetLayerNormWeights(tensorInfo20, forgetGateBiasData);
3413
3414 std::vector<float> cellLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3415 armnn::ConstTensor cellLayerNormWeights(tensorInfo20, forgetGateBiasData);
3416
3417 std::vector<float> outLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3418 armnn::ConstTensor outLayerNormWeights(tensorInfo20, forgetGateBiasData);
3419
3420 armnn::LstmInputParams params;
3421 params.m_InputToForgetWeights = &inputToForgetWeights;
3422 params.m_InputToCellWeights = &inputToCellWeights;
3423 params.m_InputToOutputWeights = &inputToOutputWeights;
3424 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3425 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3426 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3427 params.m_ForgetGateBias = &forgetGateBias;
3428 params.m_CellBias = &cellBias;
3429 params.m_OutputGateBias = &outputGateBias;
3430
3431 // additional params because: descriptor.m_CifgEnabled = false
3432 params.m_InputToInputWeights = &inputToInputWeights;
3433 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3434 params.m_CellToInputWeights = &cellToInputWeights;
3435 params.m_InputGateBias = &inputGateBias;
3436
3437 // additional params because: descriptor.m_ProjectionEnabled = true
3438 params.m_ProjectionWeights = &projectionWeights;
3439 params.m_ProjectionBias = &projectionBias;
3440
3441 // additional params because: descriptor.m_PeepholeEnabled = true
3442 params.m_CellToForgetWeights = &cellToForgetWeights;
3443 params.m_CellToOutputWeights = &cellToOutputWeights;
3444
3445 // additional params because: despriptor.m_LayerNormEnabled = true
3446 params.m_InputLayerNormWeights = &inputLayerNormWeights;
3447 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3448 params.m_CellLayerNormWeights = &cellLayerNormWeights;
3449 params.m_OutputLayerNormWeights = &outLayerNormWeights;
3450
3451 armnn::INetworkPtr network = armnn::INetwork::Create();
3452 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3453 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3454 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3455 const std::string layerName("lstm");
3456 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3457 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3458 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3459 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3460 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3461
3462 // connect up
3463 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3464 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3465 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3466 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3467
3468 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3469 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3470
3471 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3472 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3473
3474 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3475 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3476
3477 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3478 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3479
3480 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3481 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3482
3483 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3484 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3485
3486 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3487 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3488
3489 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3490 BOOST_CHECK(deserializedNetwork);
3491
3492 VerifyLstmLayer checker(
3493 layerName,
3494 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3495 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3496 descriptor,
3497 params);
3498 deserializedNetwork->Accept(checker);
3499}
3500
3501BOOST_AUTO_TEST_CASE(EnsureLstmLayersBackwardCompatibility)
3502{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003503 // The hex data below is a flat buffer containing a lstm layer with no Cifg, with peephole and projection
3504 // enabled. That data was obtained before additional layer normalization parameters where added to the
3505 // lstm serializer. That way it can be tested if a lstm model with the old parameter configuration can
3506 // still be loaded
3507 const std::vector<uint8_t> lstmNoCifgWithPeepholeAndProjectionModel =
Jan Eilersf8c62972019-07-17 11:07:49 +01003508 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003509 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
3510 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
3511 0xDC, 0x29, 0x00, 0x00, 0x38, 0x29, 0x00, 0x00, 0xB4, 0x28, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x3C, 0x01,
3512 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
3513 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
3514 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0xD6, 0xFF, 0xFF,
3515 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x06, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x88, 0xD7,
3516 0xFF, 0xFF, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF6, 0xD6, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
3517 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
3518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3519 0xE8, 0xD7, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xFF, 0xFF, 0x00, 0x00,
3520 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x5E, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xE0, 0xD7, 0xFF, 0xFF,
3521 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4E, 0xD7, 0xFF, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00,
3522 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3523 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD8,
3524 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
3525 0x04, 0x00, 0x00, 0x00, 0xB6, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x38, 0xD8, 0xFF, 0xFF, 0x08, 0x00,
3526 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA6, 0xD7, 0xFF, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3527 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3528 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xD8, 0xFF, 0xFF,
3529 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00,
3530 0x00, 0x00, 0x0E, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x16, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3531 0xFA, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00,
3532 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3533 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
3534 0x00, 0x00, 0x6C, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
3535 0x12, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE0, 0x25, 0x00, 0x00, 0xD0, 0x25,
3536 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x48, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00,
3537 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2C, 0x00, 0x30, 0x00,
3538 0x34, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x40, 0x00, 0x44, 0x00, 0x26, 0x00, 0x00, 0x00, 0xC4, 0x23, 0x00, 0x00,
3539 0xF8, 0x21, 0x00, 0x00, 0x2C, 0x20, 0x00, 0x00, 0xF0, 0x1A, 0x00, 0x00, 0xB4, 0x15, 0x00, 0x00, 0x78, 0x10,
3540 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x68, 0x0F, 0x00, 0x00, 0xE0, 0x0E, 0x00, 0x00, 0x14, 0x0D, 0x00, 0x00,
3541 0xD8, 0x07, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0xC8, 0x06, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x14, 0x01,
3542 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3543 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00,
3544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3549 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x72, 0xD8,
3550 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0xD9, 0xFF, 0xFF,
3551 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xD8,
3556 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3557 0x14, 0x00, 0x00, 0x00, 0xF6, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x54, 0x00, 0x00, 0x00, 0x04, 0x00,
3558 0x00, 0x00, 0x06, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xD9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3563 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6A, 0xD9, 0xFF, 0xFF, 0x00, 0x00,
3564 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7A, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3565 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3581 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xDE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3637 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xA2, 0xDE,
3638 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB2, 0xDF, 0xFF, 0xFF,
3639 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xDF,
3644 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3645 0x14, 0x00, 0x00, 0x00, 0x26, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00,
3646 0x00, 0x00, 0x36, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3651 0x00, 0x00, 0x00, 0x00, 0x92, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3652 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAA, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3653 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xBA, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3663 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3690 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3693 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3694 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3695 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3696 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3700 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3703 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3704 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3705 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3706 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3707 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3708 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3709 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3711 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3712 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3716 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3717 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3718 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3720 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3721 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3722 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3725 0x00, 0x00, 0x00, 0x00, 0xC6, 0xE4, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3726 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xE2, 0xE4, 0xFF, 0xFF,
3727 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xE5, 0xFF, 0xFF, 0x04, 0x00,
3728 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3729 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3730 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3732 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3733 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3734 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3735 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3736 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3737 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3738 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3739 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3740 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3741 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3746 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3751 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
3752 0x00, 0x00, 0xAA, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3753 0xBA, 0xE7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3755 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3758 0x00, 0x00, 0x16, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3759 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2E, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00,
3760 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3E, 0xE8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
3761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xB2, 0xE7, 0xFF, 0xFF,
3767 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC2, 0xE8, 0xFF, 0xFF, 0x04, 0x00,
3768 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE8, 0xFF, 0xFF,
3773 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00,
3774 0x00, 0x00, 0x36, 0xE8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3775 0x46, 0xE9, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3786 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3788 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3791 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3793 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3805 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0xFF, 0xFF,
3847 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00,
3848 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6E, 0xED, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00,
3849 0x04, 0x00, 0x00, 0x00, 0x7E, 0xEE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00,
3850 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3851 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3859 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3860 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3862 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3863 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3864 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3865 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3866 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3868 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3869 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3870 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3873 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3874 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3875 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3876 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3877 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3878 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3879 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3880 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3881 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3882 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3883 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3884 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3885 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3886 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3889 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3892 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3894 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3896 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3897 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3898 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3899 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3900 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3901 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3902 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3903 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3904 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3905 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3906 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3907 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3908 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3909 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3910 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3911 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3912 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3913 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3915 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3916 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3917 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3918 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3919 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3920 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3921 0x8A, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3922 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xA6, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3923 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB6, 0xF3, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3924 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3925 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3927 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3929 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3930 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3931 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3932 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3933 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3935 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3936 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3938 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3939 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3940 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3941 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3942 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3943 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3944 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3945 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3946 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3947 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3948 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3949 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3950 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3951 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3952 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3953 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3954 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3955 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3956 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3957 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3958 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3959 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3960 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3961 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3962 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3963 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3964 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3965 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3966 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3967 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3968 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3969 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3970 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3971 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3972 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3973 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3974 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3975 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3976 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3977 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3986 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3988 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3992 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3993 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3994 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3995 0x00, 0x00, 0x00, 0x00, 0xC2, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3996 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xDE, 0xF7, 0xFF, 0xFF,
3997 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xF8, 0xFF, 0xFF, 0x04, 0x00,
3998 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3999 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4000 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4001 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4002 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4004 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4006 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4007 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4009 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4010 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4011 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4012 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4013 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4014 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4015 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4016 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4017 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4019 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4020 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
4021 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
4022 0x00, 0x00, 0xA6, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4023 0xB6, 0xFA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4024 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4026 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4030 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4034 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4035 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4037 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xFB,
4046 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
4047 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6E, 0xFB, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01,
4048 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFC, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
4049 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4050 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4059 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4062 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4063 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4064 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4065 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4068 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4069 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4070 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4071 0x00, 0x00, 0x00, 0x00, 0x1A, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4072 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x00,
4073 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
4074 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x2E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4075 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6C, 0x73,
4076 0x74, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00,
4077 0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x30, 0x00,
4078 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4079 0xA6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
4080 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
4081 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4082 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x64, 0xFF, 0xFF, 0xFF,
4083 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4084 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4085 0xB4, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x1A, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4086 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
4087 0xF0, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
4088 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
4089 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4090 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
4091 0x7E, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00,
4092 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x76, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
4093 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
4094 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4095 0x68, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4097 0x08, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00,
4098 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4099 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00,
4100 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00,
4101 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
4102 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4103 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4104 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6E, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
4105 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00,
4106 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
4107 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00,
4108 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4109 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
4110 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4111 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4112 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00,
4113 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
4114 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00
4115 };
4116
4117 armnn::INetworkPtr deserializedNetwork =
4118 DeserializeNetwork(std::string(lstmNoCifgWithPeepholeAndProjectionModel.begin(),
4119 lstmNoCifgWithPeepholeAndProjectionModel.end()));
4120
Jan Eilersf8c62972019-07-17 11:07:49 +01004121 BOOST_CHECK(deserializedNetwork);
4122
4123 // generating the same model parameters which where used to serialize the model (Layer norm is not specified)
4124 armnn::LstmDescriptor descriptor;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004125 descriptor.m_ActivationFunc = 4;
Jan Eilersf8c62972019-07-17 11:07:49 +01004126 descriptor.m_ClippingThresProj = 0.0f;
4127 descriptor.m_ClippingThresCell = 0.0f;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004128 descriptor.m_CifgEnabled = false;
Jan Eilersf8c62972019-07-17 11:07:49 +01004129 descriptor.m_ProjectionEnabled = true;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004130 descriptor.m_PeepholeEnabled = true;
Jan Eilersf8c62972019-07-17 11:07:49 +01004131
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004132 const uint32_t batchSize = 2u;
4133 const uint32_t inputSize = 5u;
4134 const uint32_t numUnits = 20u;
4135 const uint32_t outputSize = 16u;
Jan Eilersf8c62972019-07-17 11:07:49 +01004136
4137 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
4138 std::vector<float> inputToInputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4139 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
4140
4141 std::vector<float> inputToForgetWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4142 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
4143
4144 std::vector<float> inputToCellWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4145 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
4146
4147 std::vector<float> inputToOutputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4148 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
4149
4150 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
4151 std::vector<float> inputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4152 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
4153
4154 std::vector<float> forgetGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4155 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
4156
4157 std::vector<float> cellBiasData(tensorInfo20.GetNumElements(), 0.0f);
4158 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
4159
4160 std::vector<float> outputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4161 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
4162
4163 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
4164 std::vector<float> recurrentToInputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4165 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
4166
4167 std::vector<float> recurrentToForgetWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4168 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
4169
4170 std::vector<float> recurrentToCellWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4171 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
4172
4173 std::vector<float> recurrentToOutputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4174 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
4175
4176 std::vector<float> cellToInputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4177 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
4178
4179 std::vector<float> cellToForgetWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4180 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
4181
4182 std::vector<float> cellToOutputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4183 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
4184
4185 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
4186 std::vector<float> projectionWeightsData(tensorInfo16x20.GetNumElements(), 0.0f);
4187 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
4188
4189 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
4190 std::vector<float> projectionBiasData(outputSize, 0.0f);
4191 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
4192
4193 armnn::LstmInputParams params;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004194 params.m_InputToForgetWeights = &inputToForgetWeights;
4195 params.m_InputToCellWeights = &inputToCellWeights;
4196 params.m_InputToOutputWeights = &inputToOutputWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004197 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004198 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004199 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004200 params.m_ForgetGateBias = &forgetGateBias;
4201 params.m_CellBias = &cellBias;
4202 params.m_OutputGateBias = &outputGateBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004203
4204 // additional params because: descriptor.m_CifgEnabled = false
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004205 params.m_InputToInputWeights = &inputToInputWeights;
4206 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4207 params.m_CellToInputWeights = &cellToInputWeights;
4208 params.m_InputGateBias = &inputGateBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004209
4210 // additional params because: descriptor.m_ProjectionEnabled = true
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004211 params.m_ProjectionWeights = &projectionWeights;
4212 params.m_ProjectionBias = &projectionBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004213
4214 // additional params because: descriptor.m_PeepholeEnabled = true
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004215 params.m_CellToForgetWeights = &cellToForgetWeights;
4216 params.m_CellToOutputWeights = &cellToOutputWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004217
4218 const std::string layerName("lstm");
4219 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
4220 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
4221 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
4222 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
4223
Jan Eilersf8c62972019-07-17 11:07:49 +01004224 VerifyLstmLayer checker(
4225 layerName,
4226 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
4227 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4228 descriptor,
4229 params);
4230 deserializedNetwork->Accept(checker);
4231}
Jan Eilers5b01a892019-07-23 09:47:43 +01004232class VerifyQuantizedLstmLayer : public LayerVerifierBase
4233{
4234
4235public:
4236 VerifyQuantizedLstmLayer(const std::string& layerName,
4237 const std::vector<armnn::TensorInfo>& inputInfos,
4238 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01004239 const armnn::QuantizedLstmInputParams& inputParams)
4240 : LayerVerifierBase(layerName, inputInfos, outputInfos), m_InputParams(inputParams) {}
Jan Eilers5b01a892019-07-23 09:47:43 +01004241
4242 void VisitQuantizedLstmLayer(const armnn::IConnectableLayer* layer,
4243 const armnn::QuantizedLstmInputParams& params,
4244 const char* name)
4245 {
4246 VerifyNameAndConnections(layer, name);
4247 VerifyInputParameters(params);
4248 }
4249
4250protected:
4251 void VerifyInputParameters(const armnn::QuantizedLstmInputParams& params)
4252 {
4253 VerifyConstTensors("m_InputToInputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004254 m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004255 VerifyConstTensors("m_InputToForgetWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004256 m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004257 VerifyConstTensors("m_InputToCellWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004258 m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004259 VerifyConstTensors("m_InputToOutputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004260 m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004261 VerifyConstTensors("m_RecurrentToInputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004262 m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004263 VerifyConstTensors("m_RecurrentToForgetWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004264 m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004265 VerifyConstTensors("m_RecurrentToCellWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004266 m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004267 VerifyConstTensors("m_RecurrentToOutputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004268 m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004269 VerifyConstTensors("m_InputGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004270 m_InputParams.m_InputGateBias, params.m_InputGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004271 VerifyConstTensors("m_ForgetGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004272 m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004273 VerifyConstTensors("m_CellBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004274 m_InputParams.m_CellBias, params.m_CellBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004275 VerifyConstTensors("m_OutputGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004276 m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004277 }
4278
4279private:
4280 armnn::QuantizedLstmInputParams m_InputParams;
4281};
4282
4283BOOST_AUTO_TEST_CASE(SerializeDeserializeQuantizedLstm)
4284{
4285 const uint32_t batchSize = 1;
4286 const uint32_t inputSize = 2;
4287 const uint32_t numUnits = 4;
4288 const uint32_t outputSize = numUnits;
4289
alanhsu567886324fc2019-10-25 23:44:16 +08004290 // Scale/Offset for input/output, cellState In/Out, weights, bias
4291 float inputOutputScale = 0.0078125f;
4292 int32_t inputOutputOffset = 128;
Jan Eilers5b01a892019-07-23 09:47:43 +01004293
alanhsu567886324fc2019-10-25 23:44:16 +08004294 float cellStateScale = 0.00048828125f;
4295 int32_t cellStateOffset = 0;
Jan Eilers5b01a892019-07-23 09:47:43 +01004296
alanhsu567886324fc2019-10-25 23:44:16 +08004297 float weightsScale = 0.00408021f;
4298 int32_t weightsOffset = 100;
Jan Eilers5b01a892019-07-23 09:47:43 +01004299
alanhsu567886324fc2019-10-25 23:44:16 +08004300 float biasScale = 3.1876640625e-05f;
4301 int32_t biasOffset = 0;
Jan Eilers5b01a892019-07-23 09:47:43 +01004302
alanhsu567886324fc2019-10-25 23:44:16 +08004303 // The shape of weight data is {outputSize, inputSize} = {4, 2}
4304 armnn::TensorShape inputToInputWeightsShape = {4, 2};
4305 std::vector<uint8_t> inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4306 armnn::TensorInfo inputToInputWeightsInfo(inputToInputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004307 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004308 weightsScale,
4309 weightsOffset);
4310 armnn::ConstTensor inputToInputWeights(inputToInputWeightsInfo, inputToInputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004311
alanhsu567886324fc2019-10-25 23:44:16 +08004312 armnn::TensorShape inputToForgetWeightsShape = {4, 2};
4313 std::vector<uint8_t> inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4314 armnn::TensorInfo inputToForgetWeightsInfo(inputToForgetWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004315 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004316 weightsScale,
4317 weightsOffset);
4318 armnn::ConstTensor inputToForgetWeights(inputToForgetWeightsInfo, inputToForgetWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004319
alanhsu567886324fc2019-10-25 23:44:16 +08004320 armnn::TensorShape inputToCellWeightsShape = {4, 2};
4321 std::vector<uint8_t> inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4322 armnn::TensorInfo inputToCellWeightsInfo(inputToCellWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004323 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004324 weightsScale,
4325 weightsOffset);
4326 armnn::ConstTensor inputToCellWeights(inputToCellWeightsInfo, inputToCellWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004327
alanhsu567886324fc2019-10-25 23:44:16 +08004328 armnn::TensorShape inputToOutputWeightsShape = {4, 2};
4329 std::vector<uint8_t> inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4330 armnn::TensorInfo inputToOutputWeightsInfo(inputToOutputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004331 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004332 weightsScale,
4333 weightsOffset);
4334 armnn::ConstTensor inputToOutputWeights(inputToOutputWeightsInfo, inputToOutputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004335
alanhsu567886324fc2019-10-25 23:44:16 +08004336 // The shape of recurrent weight data is {outputSize, outputSize} = {4, 4}
4337 armnn::TensorShape recurrentToInputWeightsShape = {4, 4};
4338 std::vector<uint8_t> recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4339 armnn::TensorInfo recurrentToInputWeightsInfo(recurrentToInputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004340 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004341 weightsScale,
4342 weightsOffset);
4343 armnn::ConstTensor recurrentToInputWeights(recurrentToInputWeightsInfo, recurrentToInputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004344
alanhsu567886324fc2019-10-25 23:44:16 +08004345 armnn::TensorShape recurrentToForgetWeightsShape = {4, 4};
4346 std::vector<uint8_t> recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4347 armnn::TensorInfo recurrentToForgetWeightsInfo(recurrentToForgetWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004348 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004349 weightsScale,
4350 weightsOffset);
4351 armnn::ConstTensor recurrentToForgetWeights(recurrentToForgetWeightsInfo, recurrentToForgetWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004352
alanhsu567886324fc2019-10-25 23:44:16 +08004353 armnn::TensorShape recurrentToCellWeightsShape = {4, 4};
4354 std::vector<uint8_t> recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4355 armnn::TensorInfo recurrentToCellWeightsInfo(recurrentToCellWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004356 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004357 weightsScale,
4358 weightsOffset);
4359 armnn::ConstTensor recurrentToCellWeights(recurrentToCellWeightsInfo, recurrentToCellWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004360
alanhsu567886324fc2019-10-25 23:44:16 +08004361 armnn::TensorShape recurrentToOutputWeightsShape = {4, 4};
4362 std::vector<uint8_t> recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4363 armnn::TensorInfo recurrentToOutputWeightsInfo(recurrentToOutputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004364 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004365 weightsScale,
4366 weightsOffset);
4367 armnn::ConstTensor recurrentToOutputWeights(recurrentToOutputWeightsInfo, recurrentToOutputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004368
alanhsu567886324fc2019-10-25 23:44:16 +08004369 // The shape of bias data is {outputSize} = {4}
4370 armnn::TensorShape inputGateBiasShape = {4};
4371 std::vector<int32_t> inputGateBiasData = {1, 2, 3, 4};
4372 armnn::TensorInfo inputGateBiasInfo(inputGateBiasShape,
4373 armnn::DataType::Signed32,
4374 biasScale,
4375 biasOffset);
4376 armnn::ConstTensor inputGateBias(inputGateBiasInfo, inputGateBiasData);
4377
4378 armnn::TensorShape forgetGateBiasShape = {4};
4379 std::vector<int32_t> forgetGateBiasData = {1, 2, 3, 4};
4380 armnn::TensorInfo forgetGateBiasInfo(forgetGateBiasShape,
4381 armnn::DataType::Signed32,
4382 biasScale,
4383 biasOffset);
4384 armnn::ConstTensor forgetGateBias(forgetGateBiasInfo, forgetGateBiasData);
4385
4386 armnn::TensorShape cellBiasShape = {4};
4387 std::vector<int32_t> cellBiasData = {1, 2, 3, 4};
4388 armnn::TensorInfo cellBiasInfo(cellBiasShape,
4389 armnn::DataType::Signed32,
4390 biasScale,
4391 biasOffset);
4392 armnn::ConstTensor cellBias(cellBiasInfo, cellBiasData);
4393
4394 armnn::TensorShape outputGateBiasShape = {4};
4395 std::vector<int32_t> outputGateBiasData = {1, 2, 3, 4};
4396 armnn::TensorInfo outputGateBiasInfo(outputGateBiasShape,
4397 armnn::DataType::Signed32,
4398 biasScale,
4399 biasOffset);
4400 armnn::ConstTensor outputGateBias(outputGateBiasInfo, outputGateBiasData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004401
4402 armnn::QuantizedLstmInputParams params;
4403 params.m_InputToInputWeights = &inputToInputWeights;
4404 params.m_InputToForgetWeights = &inputToForgetWeights;
4405 params.m_InputToCellWeights = &inputToCellWeights;
4406 params.m_InputToOutputWeights = &inputToOutputWeights;
4407 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4408 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4409 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4410 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4411 params.m_InputGateBias = &inputGateBias;
4412 params.m_ForgetGateBias = &forgetGateBias;
4413 params.m_CellBias = &cellBias;
4414 params.m_OutputGateBias = &outputGateBias;
4415
4416 armnn::INetworkPtr network = armnn::INetwork::Create();
alanhsu567886324fc2019-10-25 23:44:16 +08004417 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
Jan Eilers5b01a892019-07-23 09:47:43 +01004418 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
4419 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
4420 const std::string layerName("QuantizedLstm");
4421 armnn::IConnectableLayer* const quantizedLstmLayer = network->AddQuantizedLstmLayer(params, layerName.c_str());
alanhsu567886324fc2019-10-25 23:44:16 +08004422 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(0);
4423 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(1);
Jan Eilers5b01a892019-07-23 09:47:43 +01004424
alanhsu567886324fc2019-10-25 23:44:16 +08004425 // Connect up
4426 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004427 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004428 inputOutputScale,
4429 inputOutputOffset);
4430 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004431 armnn::DataType::QSymmS16,
alanhsu567886324fc2019-10-25 23:44:16 +08004432 cellStateScale,
4433 cellStateOffset);
4434 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004435 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004436 inputOutputScale,
4437 inputOutputOffset);
Jan Eilers5b01a892019-07-23 09:47:43 +01004438
4439 inputLayer->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(0));
4440 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
4441
4442 cellStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(1));
4443 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4444
4445 outputStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(2));
4446 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
4447
4448 quantizedLstmLayer->GetOutputSlot(0).Connect(cellStateOut->GetInputSlot(0));
4449 quantizedLstmLayer->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4450
4451 quantizedLstmLayer->GetOutputSlot(1).Connect(outputLayer->GetInputSlot(0));
4452 quantizedLstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
4453
4454 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4455 BOOST_CHECK(deserializedNetwork);
4456
alanhsu567886324fc2019-10-25 23:44:16 +08004457 VerifyQuantizedLstmLayer checker(layerName,
4458 {inputTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4459 {cellStateTensorInfo, outputStateTensorInfo},
4460 params);
Jan Eilers5b01a892019-07-23 09:47:43 +01004461
4462 deserializedNetwork->Accept(checker);
4463}
4464
James Conroy8d333182020-05-13 10:27:58 +01004465class VerifyQLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>
4466{
4467public:
4468 VerifyQLstmLayer(const std::string& layerName,
4469 const std::vector<armnn::TensorInfo>& inputInfos,
4470 const std::vector<armnn::TensorInfo>& outputInfos,
4471 const armnn::QLstmDescriptor& descriptor,
4472 const armnn::LstmInputParams& inputParams)
4473 : LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
4474 , m_InputParams(inputParams) {}
4475
4476 void VisitQLstmLayer(const armnn::IConnectableLayer* layer,
4477 const armnn::QLstmDescriptor& descriptor,
4478 const armnn::LstmInputParams& params,
4479 const char* name)
4480 {
4481 VerifyNameAndConnections(layer, name);
4482 VerifyDescriptor(descriptor);
4483 VerifyInputParameters(params);
4484 }
4485
4486protected:
4487 void VerifyInputParameters(const armnn::LstmInputParams& params)
4488 {
4489 VerifyConstTensors(
4490 "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4491 VerifyConstTensors(
4492 "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4493 VerifyConstTensors(
4494 "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4495 VerifyConstTensors(
4496 "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4497 VerifyConstTensors(
4498 "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4499 VerifyConstTensors(
4500 "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4501 VerifyConstTensors(
4502 "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4503 VerifyConstTensors(
4504 "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4505 VerifyConstTensors(
4506 "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
4507 VerifyConstTensors(
4508 "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
4509 VerifyConstTensors(
4510 "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
4511 VerifyConstTensors(
4512 "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
4513 VerifyConstTensors(
4514 "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4515 VerifyConstTensors(
4516 "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
4517 VerifyConstTensors(
4518 "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4519 VerifyConstTensors(
4520 "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
4521 VerifyConstTensors(
4522 "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
4523 VerifyConstTensors(
4524 "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
4525 VerifyConstTensors(
4526 "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
4527 VerifyConstTensors(
4528 "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
4529 VerifyConstTensors(
4530 "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
4531 }
4532
4533private:
4534 armnn::LstmInputParams m_InputParams;
4535};
4536
4537BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmBasic)
4538{
4539 armnn::QLstmDescriptor descriptor;
4540
4541 descriptor.m_CifgEnabled = true;
4542 descriptor.m_ProjectionEnabled = false;
4543 descriptor.m_PeepholeEnabled = false;
4544 descriptor.m_LayerNormEnabled = false;
4545
4546 descriptor.m_CellClip = 0.0f;
4547 descriptor.m_ProjectionClip = 0.0f;
4548
4549 descriptor.m_InputIntermediateScale = 0.00001f;
4550 descriptor.m_ForgetIntermediateScale = 0.00001f;
4551 descriptor.m_CellIntermediateScale = 0.00001f;
4552 descriptor.m_OutputIntermediateScale = 0.00001f;
4553
4554 descriptor.m_HiddenStateScale = 0.07f;
4555 descriptor.m_HiddenStateZeroPoint = 0;
4556
4557 const unsigned int numBatches = 2;
4558 const unsigned int inputSize = 5;
4559 const unsigned int outputSize = 4;
4560 const unsigned int numUnits = 4;
4561
4562 // Scale/Offset quantization info
4563 float inputScale = 0.0078f;
4564 int32_t inputOffset = 0;
4565
4566 float outputScale = 0.0078f;
4567 int32_t outputOffset = 0;
4568
4569 float cellStateScale = 3.5002e-05f;
4570 int32_t cellStateOffset = 0;
4571
4572 float weightsScale = 0.007f;
4573 int32_t weightsOffset = 0;
4574
4575 float biasScale = 3.5002e-05f / 1024;
4576 int32_t biasOffset = 0;
4577
4578 // Weights and bias tensor and quantization info
4579 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4580 armnn::DataType::QSymmS8,
4581 weightsScale,
4582 weightsOffset);
4583
4584 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4585 armnn::DataType::QSymmS8,
4586 weightsScale,
4587 weightsOffset);
4588
4589 armnn::TensorInfo biasInfo({numUnits}, armnn::DataType::Signed32, biasScale, biasOffset);
4590
4591 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4592 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4593 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4594
4595 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4596 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4597 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4598
4599 std::vector<int8_t> recurrentToForgetWeightsData =
4600 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4601 std::vector<int8_t> recurrentToCellWeightsData =
4602 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4603 std::vector<int8_t> recurrentToOutputWeightsData =
4604 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4605
4606 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4607 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4608 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4609
4610 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4611 std::vector<int32_t> cellBiasData(numUnits, 0);
4612 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4613
4614 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4615 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4616 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4617
4618 // Set up params
4619 armnn::LstmInputParams params;
4620 params.m_InputToForgetWeights = &inputToForgetWeights;
4621 params.m_InputToCellWeights = &inputToCellWeights;
4622 params.m_InputToOutputWeights = &inputToOutputWeights;
4623
4624 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4625 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4626 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4627
4628 params.m_ForgetGateBias = &forgetGateBias;
4629 params.m_CellBias = &cellBias;
4630 params.m_OutputGateBias = &outputGateBias;
4631
4632 // Create network
4633 armnn::INetworkPtr network = armnn::INetwork::Create();
4634 const std::string layerName("qLstm");
4635
4636 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4637 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4638 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4639
4640 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4641
4642 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4643 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4644 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4645
4646 // Input/Output tensor info
4647 armnn::TensorInfo inputInfo({numBatches , inputSize},
4648 armnn::DataType::QAsymmS8,
4649 inputScale,
4650 inputOffset);
4651
4652 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4653 armnn::DataType::QSymmS16,
4654 cellStateScale,
4655 cellStateOffset);
4656
4657 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4658 armnn::DataType::QAsymmS8,
4659 outputScale,
4660 outputOffset);
4661
4662 // Connect input/output slots
4663 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4664 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4665
4666 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4667 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4668
4669 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4670 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4671
4672 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4673 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4674
4675 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4676 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4677
4678 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4679 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4680
4681 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4682 BOOST_CHECK(deserializedNetwork);
4683
4684 VerifyQLstmLayer checker(layerName,
4685 {inputInfo, cellStateInfo, outputStateInfo},
4686 {outputStateInfo, cellStateInfo, outputStateInfo},
4687 descriptor,
4688 params);
4689
4690 deserializedNetwork->Accept(checker);
4691}
4692
4693BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmCifgLayerNorm)
4694{
4695 armnn::QLstmDescriptor descriptor;
4696
4697 // CIFG params are used when CIFG is disabled
4698 descriptor.m_CifgEnabled = true;
4699 descriptor.m_ProjectionEnabled = false;
4700 descriptor.m_PeepholeEnabled = false;
4701 descriptor.m_LayerNormEnabled = true;
4702
4703 descriptor.m_CellClip = 0.0f;
4704 descriptor.m_ProjectionClip = 0.0f;
4705
4706 descriptor.m_InputIntermediateScale = 0.00001f;
4707 descriptor.m_ForgetIntermediateScale = 0.00001f;
4708 descriptor.m_CellIntermediateScale = 0.00001f;
4709 descriptor.m_OutputIntermediateScale = 0.00001f;
4710
4711 descriptor.m_HiddenStateScale = 0.07f;
4712 descriptor.m_HiddenStateZeroPoint = 0;
4713
4714 const unsigned int numBatches = 2;
4715 const unsigned int inputSize = 5;
4716 const unsigned int outputSize = 4;
4717 const unsigned int numUnits = 4;
4718
4719 // Scale/Offset quantization info
4720 float inputScale = 0.0078f;
4721 int32_t inputOffset = 0;
4722
4723 float outputScale = 0.0078f;
4724 int32_t outputOffset = 0;
4725
4726 float cellStateScale = 3.5002e-05f;
4727 int32_t cellStateOffset = 0;
4728
4729 float weightsScale = 0.007f;
4730 int32_t weightsOffset = 0;
4731
4732 float layerNormScale = 3.5002e-05f;
4733 int32_t layerNormOffset = 0;
4734
4735 float biasScale = layerNormScale / 1024;
4736 int32_t biasOffset = 0;
4737
4738 // Weights and bias tensor and quantization info
4739 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4740 armnn::DataType::QSymmS8,
4741 weightsScale,
4742 weightsOffset);
4743
4744 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4745 armnn::DataType::QSymmS8,
4746 weightsScale,
4747 weightsOffset);
4748
4749 armnn::TensorInfo biasInfo({numUnits},
4750 armnn::DataType::Signed32,
4751 biasScale,
4752 biasOffset);
4753
4754 armnn::TensorInfo layerNormWeightsInfo({numUnits},
4755 armnn::DataType::QSymmS16,
4756 layerNormScale,
4757 layerNormOffset);
4758
4759 // Mandatory params
4760 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4761 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4762 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4763
4764 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4765 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4766 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4767
4768 std::vector<int8_t> recurrentToForgetWeightsData =
4769 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4770 std::vector<int8_t> recurrentToCellWeightsData =
4771 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4772 std::vector<int8_t> recurrentToOutputWeightsData =
4773 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4774
4775 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4776 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4777 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4778
4779 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4780 std::vector<int32_t> cellBiasData(numUnits, 0);
4781 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4782
4783 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4784 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4785 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4786
4787 // Layer Norm
4788 std::vector<int16_t> forgetLayerNormWeightsData =
4789 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4790 std::vector<int16_t> cellLayerNormWeightsData =
4791 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4792 std::vector<int16_t> outputLayerNormWeightsData =
4793 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4794
4795 armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
4796 armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
4797 armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
4798
4799 // Set up params
4800 armnn::LstmInputParams params;
4801
4802 // Mandatory params
4803 params.m_InputToForgetWeights = &inputToForgetWeights;
4804 params.m_InputToCellWeights = &inputToCellWeights;
4805 params.m_InputToOutputWeights = &inputToOutputWeights;
4806
4807 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4808 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4809 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4810
4811 params.m_ForgetGateBias = &forgetGateBias;
4812 params.m_CellBias = &cellBias;
4813 params.m_OutputGateBias = &outputGateBias;
4814
4815 // Layer Norm
4816 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
4817 params.m_CellLayerNormWeights = &cellLayerNormWeights;
4818 params.m_OutputLayerNormWeights = &outputLayerNormWeights;
4819
4820 // Create network
4821 armnn::INetworkPtr network = armnn::INetwork::Create();
4822 const std::string layerName("qLstm");
4823
4824 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4825 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4826 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4827
4828 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4829
4830 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4831 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4832 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4833
4834 // Input/Output tensor info
4835 armnn::TensorInfo inputInfo({numBatches , inputSize},
4836 armnn::DataType::QAsymmS8,
4837 inputScale,
4838 inputOffset);
4839
4840 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4841 armnn::DataType::QSymmS16,
4842 cellStateScale,
4843 cellStateOffset);
4844
4845 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4846 armnn::DataType::QAsymmS8,
4847 outputScale,
4848 outputOffset);
4849
4850 // Connect input/output slots
4851 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4852 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4853
4854 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4855 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4856
4857 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4858 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4859
4860 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4861 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4862
4863 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4864 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4865
4866 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4867 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4868
4869 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4870 BOOST_CHECK(deserializedNetwork);
4871
4872 VerifyQLstmLayer checker(layerName,
4873 {inputInfo, cellStateInfo, outputStateInfo},
4874 {outputStateInfo, cellStateInfo, outputStateInfo},
4875 descriptor,
4876 params);
4877
4878 deserializedNetwork->Accept(checker);
4879}
4880
4881BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmAdvanced)
4882{
4883 armnn::QLstmDescriptor descriptor;
4884
4885 descriptor.m_CifgEnabled = false;
4886 descriptor.m_ProjectionEnabled = true;
4887 descriptor.m_PeepholeEnabled = true;
4888 descriptor.m_LayerNormEnabled = true;
4889
4890 descriptor.m_CellClip = 0.1f;
4891 descriptor.m_ProjectionClip = 0.1f;
4892
4893 descriptor.m_InputIntermediateScale = 0.00001f;
4894 descriptor.m_ForgetIntermediateScale = 0.00001f;
4895 descriptor.m_CellIntermediateScale = 0.00001f;
4896 descriptor.m_OutputIntermediateScale = 0.00001f;
4897
4898 descriptor.m_HiddenStateScale = 0.07f;
4899 descriptor.m_HiddenStateZeroPoint = 0;
4900
4901 const unsigned int numBatches = 2;
4902 const unsigned int inputSize = 5;
4903 const unsigned int outputSize = 4;
4904 const unsigned int numUnits = 4;
4905
4906 // Scale/Offset quantization info
4907 float inputScale = 0.0078f;
4908 int32_t inputOffset = 0;
4909
4910 float outputScale = 0.0078f;
4911 int32_t outputOffset = 0;
4912
4913 float cellStateScale = 3.5002e-05f;
4914 int32_t cellStateOffset = 0;
4915
4916 float weightsScale = 0.007f;
4917 int32_t weightsOffset = 0;
4918
4919 float layerNormScale = 3.5002e-05f;
4920 int32_t layerNormOffset = 0;
4921
4922 float biasScale = layerNormScale / 1024;
4923 int32_t biasOffset = 0;
4924
4925 // Weights and bias tensor and quantization info
4926 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4927 armnn::DataType::QSymmS8,
4928 weightsScale,
4929 weightsOffset);
4930
4931 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4932 armnn::DataType::QSymmS8,
4933 weightsScale,
4934 weightsOffset);
4935
4936 armnn::TensorInfo biasInfo({numUnits},
4937 armnn::DataType::Signed32,
4938 biasScale,
4939 biasOffset);
4940
4941 armnn::TensorInfo peepholeWeightsInfo({numUnits},
4942 armnn::DataType::QSymmS16,
4943 weightsScale,
4944 weightsOffset);
4945
4946 armnn::TensorInfo layerNormWeightsInfo({numUnits},
4947 armnn::DataType::QSymmS16,
4948 layerNormScale,
4949 layerNormOffset);
4950
4951 armnn::TensorInfo projectionWeightsInfo({outputSize, numUnits},
4952 armnn::DataType::QSymmS8,
4953 weightsScale,
4954 weightsOffset);
4955
4956 // Mandatory params
4957 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4958 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4959 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4960
4961 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4962 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4963 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4964
4965 std::vector<int8_t> recurrentToForgetWeightsData =
4966 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4967 std::vector<int8_t> recurrentToCellWeightsData =
4968 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4969 std::vector<int8_t> recurrentToOutputWeightsData =
4970 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4971
4972 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4973 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4974 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4975
4976 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4977 std::vector<int32_t> cellBiasData(numUnits, 0);
4978 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4979
4980 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4981 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4982 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4983
4984 // CIFG
4985 std::vector<int8_t> inputToInputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4986 std::vector<int8_t> recurrentToInputWeightsData =
4987 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4988 std::vector<int32_t> inputGateBiasData(numUnits, 1);
4989
4990 armnn::ConstTensor inputToInputWeights(inputWeightsInfo, inputToInputWeightsData);
4991 armnn::ConstTensor recurrentToInputWeights(recurrentWeightsInfo, recurrentToInputWeightsData);
4992 armnn::ConstTensor inputGateBias(biasInfo, inputGateBiasData);
4993
4994 // Peephole
4995 std::vector<int16_t> cellToInputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4996 std::vector<int16_t> cellToForgetWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4997 std::vector<int16_t> cellToOutputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4998
4999 armnn::ConstTensor cellToInputWeights(peepholeWeightsInfo, cellToInputWeightsData);
5000 armnn::ConstTensor cellToForgetWeights(peepholeWeightsInfo, cellToForgetWeightsData);
5001 armnn::ConstTensor cellToOutputWeights(peepholeWeightsInfo, cellToOutputWeightsData);
5002
5003 // Projection
5004 std::vector<int8_t> projectionWeightsData = GenerateRandomData<int8_t>(projectionWeightsInfo.GetNumElements());
5005 std::vector<int32_t> projectionBiasData(outputSize, 1);
5006
5007 armnn::ConstTensor projectionWeights(projectionWeightsInfo, projectionWeightsData);
5008 armnn::ConstTensor projectionBias(biasInfo, projectionBiasData);
5009
5010 // Layer Norm
5011 std::vector<int16_t> inputLayerNormWeightsData =
5012 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5013 std::vector<int16_t> forgetLayerNormWeightsData =
5014 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5015 std::vector<int16_t> cellLayerNormWeightsData =
5016 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5017 std::vector<int16_t> outputLayerNormWeightsData =
5018 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5019
5020 armnn::ConstTensor inputLayerNormWeights(layerNormWeightsInfo, inputLayerNormWeightsData);
5021 armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
5022 armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
5023 armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
5024
5025 // Set up params
5026 armnn::LstmInputParams params;
5027
5028 // Mandatory params
5029 params.m_InputToForgetWeights = &inputToForgetWeights;
5030 params.m_InputToCellWeights = &inputToCellWeights;
5031 params.m_InputToOutputWeights = &inputToOutputWeights;
5032
5033 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
5034 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
5035 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
5036
5037 params.m_ForgetGateBias = &forgetGateBias;
5038 params.m_CellBias = &cellBias;
5039 params.m_OutputGateBias = &outputGateBias;
5040
5041 // CIFG
5042 params.m_InputToInputWeights = &inputToInputWeights;
5043 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
5044 params.m_InputGateBias = &inputGateBias;
5045
5046 // Peephole
5047 params.m_CellToInputWeights = &cellToInputWeights;
5048 params.m_CellToForgetWeights = &cellToForgetWeights;
5049 params.m_CellToOutputWeights = &cellToOutputWeights;
5050
5051 // Projection
5052 params.m_ProjectionWeights = &projectionWeights;
5053 params.m_ProjectionBias = &projectionBias;
5054
5055 // Layer Norm
5056 params.m_InputLayerNormWeights = &inputLayerNormWeights;
5057 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
5058 params.m_CellLayerNormWeights = &cellLayerNormWeights;
5059 params.m_OutputLayerNormWeights = &outputLayerNormWeights;
5060
5061 // Create network
5062 armnn::INetworkPtr network = armnn::INetwork::Create();
5063 const std::string layerName("qLstm");
5064
5065 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
5066 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
5067 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
5068
5069 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
5070
5071 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
5072 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
5073 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
5074
5075 // Input/Output tensor info
5076 armnn::TensorInfo inputInfo({numBatches , inputSize},
5077 armnn::DataType::QAsymmS8,
5078 inputScale,
5079 inputOffset);
5080
5081 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
5082 armnn::DataType::QSymmS16,
5083 cellStateScale,
5084 cellStateOffset);
5085
5086 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
5087 armnn::DataType::QAsymmS8,
5088 outputScale,
5089 outputOffset);
5090
5091 // Connect input/output slots
5092 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
5093 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
5094
5095 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
5096 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
5097
5098 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
5099 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
5100
5101 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
5102 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
5103
5104 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
5105 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
5106
5107 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
5108 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
5109
5110 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
5111 BOOST_CHECK(deserializedNetwork);
5112
5113 VerifyQLstmLayer checker(layerName,
5114 {inputInfo, cellStateInfo, outputStateInfo},
5115 {outputStateInfo, cellStateInfo, outputStateInfo},
5116 descriptor,
5117 params);
5118
5119 deserializedNetwork->Accept(checker);
5120}
5121
Nattapat Chaimanowong30b00202019-02-20 17:31:34 +00005122BOOST_AUTO_TEST_SUITE_END()