blob: 11177f5d04d1a062800c7eaa1c2e3108e6c4c511 [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{
Finn Williams85d36712021-01-26 22:30:06 +0000240 armnnSerializer::ISerializerPtr serializer = armnnSerializer::ISerializer::Create();
241
242 serializer->Serialize(network);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000243
244 std::stringstream stream;
Finn Williams85d36712021-01-26 22:30:06 +0000245 serializer->SaveSerializedToStream(stream);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000246
247 std::string serializerString{stream.str()};
248 return serializerString;
249}
250
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000251template<typename DataType>
252static std::vector<DataType> GenerateRandomData(size_t size)
253{
254 constexpr bool isIntegerType = std::is_integral<DataType>::value;
255 using Distribution =
256 typename std::conditional<isIntegerType,
257 std::uniform_int_distribution<DataType>,
258 std::uniform_real_distribution<DataType>>::type;
259
260 static constexpr DataType lowerLimit = std::numeric_limits<DataType>::min();
261 static constexpr DataType upperLimit = std::numeric_limits<DataType>::max();
262
263 static Distribution distribution(lowerLimit, upperLimit);
264 static std::default_random_engine generator;
265
266 std::vector<DataType> randomData(size);
267 std::generate(randomData.begin(), randomData.end(), []() { return distribution(generator); });
268
269 return randomData;
270}
271
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000272} // anonymous namespace
273
274BOOST_AUTO_TEST_SUITE(SerializerTests)
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000275
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000276BOOST_AUTO_TEST_CASE(SerializeAddition)
Mike Kelly8c1701a2019-02-11 17:01:27 +0000277{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100278 DECLARE_LAYER_VERIFIER_CLASS(Addition)
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000279
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000280 const std::string layerName("addition");
281 const armnn::TensorInfo tensorInfo({1, 2, 3}, armnn::DataType::Float32);
282
Mike Kelly8c1701a2019-02-11 17:01:27 +0000283 armnn::INetworkPtr network = armnn::INetwork::Create();
284 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
285 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000286 armnn::IConnectableLayer* const additionLayer = network->AddAdditionLayer(layerName.c_str());
287 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000288
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000289 inputLayer0->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(0));
290 inputLayer1->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(1));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000291 additionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Mike Kelly8c1701a2019-02-11 17:01:27 +0000292
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000293 inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
294 inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
295 additionLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
Jim Flynn3091b062019-02-15 14:45:04 +0000296
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000297 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000298 BOOST_CHECK(deserializedNetwork);
299
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000300 AdditionLayerVerifier verifier(layerName, {tensorInfo, tensorInfo}, {tensorInfo});
301 deserializedNetwork->Accept(verifier);
302}
Jim Flynnac25a1b2019-02-28 10:40:49 +0000303
Narumol Prangnawarat0cfcf232019-09-09 17:16:24 +0100304BOOST_AUTO_TEST_CASE(SerializeArgMinMax)
305{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100306 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(ArgMinMax)
Narumol Prangnawarat0cfcf232019-09-09 17:16:24 +0100307
308 const std::string layerName("argminmax");
309 const armnn::TensorInfo inputInfo({1, 2, 3}, armnn::DataType::Float32);
310 const armnn::TensorInfo outputInfo({1, 3}, armnn::DataType::Signed32);
311
312 armnn::ArgMinMaxDescriptor descriptor;
313 descriptor.m_Function = armnn::ArgMinMaxFunction::Max;
314 descriptor.m_Axis = 1;
315
316 armnn::INetworkPtr network = armnn::INetwork::Create();
317 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
318 armnn::IConnectableLayer* const argMinMaxLayer = network->AddArgMinMaxLayer(descriptor, layerName.c_str());
319 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
320
321 inputLayer->GetOutputSlot(0).Connect(argMinMaxLayer->GetInputSlot(0));
322 argMinMaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
323
324 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
325 argMinMaxLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
326
327 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
328 BOOST_CHECK(deserializedNetwork);
329
330 ArgMinMaxLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
331 deserializedNetwork->Accept(verifier);
332}
333
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000334BOOST_AUTO_TEST_CASE(SerializeBatchNormalization)
335{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100336 using Descriptor = armnn::BatchNormalizationDescriptor;
337 class BatchNormalizationLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000338 {
339 public:
340 BatchNormalizationLayerVerifier(const std::string& layerName,
341 const std::vector<armnn::TensorInfo>& inputInfos,
342 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100343 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000344 const armnn::ConstTensor& mean,
345 const armnn::ConstTensor& variance,
346 const armnn::ConstTensor& beta,
347 const armnn::ConstTensor& gamma)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100348 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
349 , m_Mean(mean)
350 , m_Variance(variance)
351 , m_Beta(beta)
352 , m_Gamma(gamma) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000353
354 void VisitBatchNormalizationLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100355 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000356 const armnn::ConstTensor& mean,
357 const armnn::ConstTensor& variance,
358 const armnn::ConstTensor& beta,
359 const armnn::ConstTensor& gamma,
360 const char* name) override
361 {
362 VerifyNameAndConnections(layer, name);
363 VerifyDescriptor(descriptor);
364
365 CompareConstTensor(mean, m_Mean);
366 CompareConstTensor(variance, m_Variance);
367 CompareConstTensor(beta, m_Beta);
368 CompareConstTensor(gamma, m_Gamma);
369 }
370
371 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000372 armnn::ConstTensor m_Mean;
373 armnn::ConstTensor m_Variance;
374 armnn::ConstTensor m_Beta;
375 armnn::ConstTensor m_Gamma;
376 };
377
378 const std::string layerName("batchNormalization");
379 const armnn::TensorInfo inputInfo ({ 1, 3, 3, 1 }, armnn::DataType::Float32);
380 const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
381
382 const armnn::TensorInfo meanInfo({1}, armnn::DataType::Float32);
383 const armnn::TensorInfo varianceInfo({1}, armnn::DataType::Float32);
384 const armnn::TensorInfo betaInfo({1}, armnn::DataType::Float32);
385 const armnn::TensorInfo gammaInfo({1}, armnn::DataType::Float32);
386
387 armnn::BatchNormalizationDescriptor descriptor;
388 descriptor.m_Eps = 0.0010000000475f;
389 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
390
391 std::vector<float> meanData({5.0});
392 std::vector<float> varianceData({2.0});
393 std::vector<float> betaData({1.0});
394 std::vector<float> gammaData({0.0});
395
396 armnn::ConstTensor mean(meanInfo, meanData);
397 armnn::ConstTensor variance(varianceInfo, varianceData);
398 armnn::ConstTensor beta(betaInfo, betaData);
399 armnn::ConstTensor gamma(gammaInfo, gammaData);
400
401 armnn::INetworkPtr network = armnn::INetwork::Create();
402 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
403 armnn::IConnectableLayer* const batchNormalizationLayer =
404 network->AddBatchNormalizationLayer(descriptor, mean, variance, beta, gamma, layerName.c_str());
405 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
406
407 inputLayer->GetOutputSlot(0).Connect(batchNormalizationLayer->GetInputSlot(0));
408 batchNormalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
409
410 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
411 batchNormalizationLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
412
413 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
414 BOOST_CHECK(deserializedNetwork);
415
416 BatchNormalizationLayerVerifier verifier(
417 layerName, {inputInfo}, {outputInfo}, descriptor, mean, variance, beta, gamma);
418 deserializedNetwork->Accept(verifier);
419}
420
421BOOST_AUTO_TEST_CASE(SerializeBatchToSpaceNd)
422{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100423 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(BatchToSpaceNd)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000424
425 const std::string layerName("spaceToBatchNd");
426 const armnn::TensorInfo inputInfo({4, 1, 2, 2}, armnn::DataType::Float32);
427 const armnn::TensorInfo outputInfo({1, 1, 4, 4}, armnn::DataType::Float32);
428
429 armnn::BatchToSpaceNdDescriptor desc;
430 desc.m_DataLayout = armnn::DataLayout::NCHW;
431 desc.m_BlockShape = {2, 2};
432 desc.m_Crops = {{0, 0}, {0, 0}};
433
434 armnn::INetworkPtr network = armnn::INetwork::Create();
435 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
436 armnn::IConnectableLayer* const batchToSpaceNdLayer = network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
437 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
438
439 inputLayer->GetOutputSlot(0).Connect(batchToSpaceNdLayer->GetInputSlot(0));
440 batchToSpaceNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
441
442 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
443 batchToSpaceNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
444
445 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
446 BOOST_CHECK(deserializedNetwork);
447
448 BatchToSpaceNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
449 deserializedNetwork->Accept(verifier);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000450}
451
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100452BOOST_AUTO_TEST_CASE(SerializeComparison)
453{
454 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Comparison)
455
456 const std::string layerName("comparison");
457
458 const armnn::TensorShape shape{2, 1, 2, 4};
459
460 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
461 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
462
463 armnn::ComparisonDescriptor descriptor(armnn::ComparisonOperation::NotEqual);
464
465 armnn::INetworkPtr network = armnn::INetwork::Create();
466 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
467 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
468 armnn::IConnectableLayer* const comparisonLayer = network->AddComparisonLayer(descriptor, layerName.c_str());
469 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
470
471 inputLayer0->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(0));
472 inputLayer1->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(1));
473 comparisonLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
474
475 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
476 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
477 comparisonLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
478
479 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
480 BOOST_CHECK(deserializedNetwork);
481
482 ComparisonLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo }, descriptor);
483 deserializedNetwork->Accept(verifier);
484}
485
Conor Kennedy76277882019-02-26 08:29:54 +0000486BOOST_AUTO_TEST_CASE(SerializeConstant)
487{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000488 class ConstantLayerVerifier : public LayerVerifierBase
Conor Kennedy76277882019-02-26 08:29:54 +0000489 {
490 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000491 ConstantLayerVerifier(const std::string& layerName,
492 const std::vector<armnn::TensorInfo>& inputInfos,
493 const std::vector<armnn::TensorInfo>& outputInfos,
494 const armnn::ConstTensor& layerInput)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100495 : LayerVerifierBase(layerName, inputInfos, outputInfos)
496 , m_LayerInput(layerInput) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000497
498 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
499 const armnn::ConstTensor& input,
500 const char* name) override
Conor Kennedy76277882019-02-26 08:29:54 +0000501 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000502 VerifyNameAndConnections(layer, name);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000503 CompareConstTensor(input, m_LayerInput);
Conor Kennedy76277882019-02-26 08:29:54 +0000504 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000505
Derek Lamberti859f9ce2019-12-10 22:05:21 +0000506 void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000507
508 private:
509 armnn::ConstTensor m_LayerInput;
Conor Kennedy76277882019-02-26 08:29:54 +0000510 };
511
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000512 const std::string layerName("constant");
513 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
Conor Kennedy76277882019-02-26 08:29:54 +0000514
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000515 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
516 armnn::ConstTensor constTensor(info, constantData);
Conor Kennedy76277882019-02-26 08:29:54 +0000517
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000518 armnn::INetworkPtr network(armnn::INetwork::Create());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000519 armnn::IConnectableLayer* input = network->AddInputLayer(0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000520 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000521 armnn::IConnectableLayer* add = network->AddAdditionLayer();
522 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
Conor Kennedy76277882019-02-26 08:29:54 +0000523
524 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
525 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
526 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
527
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000528 input->GetOutputSlot(0).SetTensorInfo(info);
529 constant->GetOutputSlot(0).SetTensorInfo(info);
530 add->GetOutputSlot(0).SetTensorInfo(info);
Conor Kennedy76277882019-02-26 08:29:54 +0000531
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000532 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Conor Kennedy76277882019-02-26 08:29:54 +0000533 BOOST_CHECK(deserializedNetwork);
534
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000535 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
536 deserializedNetwork->Accept(verifier);
Conor Kennedy76277882019-02-26 08:29:54 +0000537}
538
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000539BOOST_AUTO_TEST_CASE(SerializeConvolution2d)
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000540{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100541 using Descriptor = armnn::Convolution2dDescriptor;
542 class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000543 {
544 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000545 Convolution2dLayerVerifier(const std::string& layerName,
546 const std::vector<armnn::TensorInfo>& inputInfos,
547 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100548 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100549 const armnn::ConstTensor& weights,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100550 const armnn::Optional<armnn::ConstTensor>& biases)
551 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
552 , m_Weights(weights)
553 , m_Biases(biases) {}
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000554
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000555 void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100556 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100557 const armnn::ConstTensor& weights,
558 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000559 const char* name) override
560 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000561 VerifyNameAndConnections(layer, name);
562 VerifyDescriptor(descriptor);
563
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100564 // check weights
565 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000566
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100567 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100568 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100569 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
570
571 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000572 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100573 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000574 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000575 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000576
577 private:
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100578 armnn::ConstTensor m_Weights;
579 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000580 };
581
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000582 const std::string layerName("convolution2d");
583 const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
584 const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
Saoirse Stewart263829c2019-02-19 15:54:14 +0000585
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000586 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
587 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000588
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000589 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
590 armnn::ConstTensor weights(weightsInfo, weightsData);
591
592 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
593 armnn::ConstTensor biases(biasesInfo, biasesData);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000594
595 armnn::Convolution2dDescriptor descriptor;
596 descriptor.m_PadLeft = 1;
597 descriptor.m_PadRight = 1;
598 descriptor.m_PadTop = 1;
599 descriptor.m_PadBottom = 1;
600 descriptor.m_StrideX = 2;
601 descriptor.m_StrideY = 2;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100602 descriptor.m_DilationX = 2;
603 descriptor.m_DilationY = 2;
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000604 descriptor.m_BiasEnabled = true;
605 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
606
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000607 armnn::INetworkPtr network = armnn::INetwork::Create();
608 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000609 armnn::IConnectableLayer* const convLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100610 network->AddConvolution2dLayer(descriptor,
611 weights,
612 armnn::Optional<armnn::ConstTensor>(biases),
613 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000614 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000615
616 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000617 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000618
619 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000620 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
621
622 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
623 BOOST_CHECK(deserializedNetwork);
624
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000625 Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
626 deserializedNetwork->Accept(verifier);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000627}
628
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000629BOOST_AUTO_TEST_CASE(SerializeConvolution2dWithPerAxisParams)
630{
631 using Descriptor = armnn::Convolution2dDescriptor;
632 class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
633 {
634 public:
635 Convolution2dLayerVerifier(const std::string& layerName,
636 const std::vector<armnn::TensorInfo>& inputInfos,
637 const std::vector<armnn::TensorInfo>& outputInfos,
638 const Descriptor& descriptor,
639 const armnn::ConstTensor& weights,
640 const armnn::Optional<armnn::ConstTensor>& biases)
641 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
642 , m_Weights(weights)
643 , m_Biases(biases) {}
644
645 void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
646 const Descriptor& descriptor,
647 const armnn::ConstTensor& weights,
648 const armnn::Optional<armnn::ConstTensor>& biases,
649 const char* name) override
650 {
651 VerifyNameAndConnections(layer, name);
652 VerifyDescriptor(descriptor);
653
654 // check weights
655 CompareConstTensor(weights, m_Weights);
656
657 // check biases
658 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
659 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
660
661 if (biases.has_value() && m_Biases.has_value())
662 {
663 CompareConstTensor(biases.value(), m_Biases.value());
664 }
665 }
666
667 private:
668 armnn::ConstTensor m_Weights;
669 armnn::Optional<armnn::ConstTensor> m_Biases;
670 };
671
672 using namespace armnn;
673
674 const std::string layerName("convolution2dWithPerAxis");
675 const TensorInfo inputInfo ({ 1, 3, 1, 2 }, DataType::QAsymmU8, 0.55f, 128);
676 const TensorInfo outputInfo({ 1, 3, 1, 3 }, DataType::QAsymmU8, 0.75f, 128);
677
678 const std::vector<float> quantScales{ 0.75f, 0.65f, 0.85f };
679 constexpr unsigned int quantDimension = 0;
680
681 const TensorInfo kernelInfo({ 3, 1, 1, 2 }, DataType::QSymmS8, quantScales, quantDimension);
682
683 const std::vector<float> biasQuantScales{ 0.25f, 0.50f, 0.75f };
684 const TensorInfo biasInfo({ 3 }, DataType::Signed32, biasQuantScales, quantDimension);
685
686 std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
687 armnn::ConstTensor weights(kernelInfo, kernelData);
688 std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
689 armnn::ConstTensor biases(biasInfo, biasData);
690
691 Convolution2dDescriptor descriptor;
692 descriptor.m_StrideX = 1;
693 descriptor.m_StrideY = 1;
694 descriptor.m_PadLeft = 0;
695 descriptor.m_PadRight = 0;
696 descriptor.m_PadTop = 0;
697 descriptor.m_PadBottom = 0;
698 descriptor.m_BiasEnabled = true;
699 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
700
701 armnn::INetworkPtr network = armnn::INetwork::Create();
702 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
703 armnn::IConnectableLayer* const convLayer =
704 network->AddConvolution2dLayer(descriptor,
705 weights,
706 armnn::Optional<armnn::ConstTensor>(biases),
707 layerName.c_str());
708 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
709
710 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
711 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
712
713 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
714 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
715
716 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
717 BOOST_CHECK(deserializedNetwork);
718
719 Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
720 deserializedNetwork->Accept(verifier);
721}
722
Aron Virginas-Tarda9d2d32019-09-20 10:42:02 +0100723BOOST_AUTO_TEST_CASE(SerializeDepthToSpace)
724{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100725 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(DepthToSpace)
Aron Virginas-Tarda9d2d32019-09-20 10:42:02 +0100726
727 const std::string layerName("depthToSpace");
728
729 const armnn::TensorInfo inputInfo ({ 1, 8, 4, 12 }, armnn::DataType::Float32);
730 const armnn::TensorInfo outputInfo({ 1, 16, 8, 3 }, armnn::DataType::Float32);
731
732 armnn::DepthToSpaceDescriptor desc;
733 desc.m_BlockSize = 2;
734 desc.m_DataLayout = armnn::DataLayout::NHWC;
735
736 armnn::INetworkPtr network = armnn::INetwork::Create();
737 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
738 armnn::IConnectableLayer* const depthToSpaceLayer = network->AddDepthToSpaceLayer(desc, layerName.c_str());
739 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
740
741 inputLayer->GetOutputSlot(0).Connect(depthToSpaceLayer->GetInputSlot(0));
742 depthToSpaceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
743
744 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
745 depthToSpaceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
746
747 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
748 BOOST_CHECK(deserializedNetwork);
749
750 DepthToSpaceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
751 deserializedNetwork->Accept(verifier);
752}
753
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000754BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2d)
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000755{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100756 using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
757 class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000758 {
759 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000760 DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
761 const std::vector<armnn::TensorInfo>& inputInfos,
762 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100763 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100764 const armnn::ConstTensor& weights,
765 const armnn::Optional<armnn::ConstTensor>& biases) :
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100766 LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100767 m_Weights(weights),
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100768 m_Biases(biases) {}
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000769
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000770 void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100771 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100772 const armnn::ConstTensor& weights,
773 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000774 const char* name) override
775 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000776 VerifyNameAndConnections(layer, name);
777 VerifyDescriptor(descriptor);
778
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100779 // check weights
780 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000781
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100782 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100783 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100784 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
785
786 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000787 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100788 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000789 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000790 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000791
792 private:
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100793 armnn::ConstTensor m_Weights;
794 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000795 };
796
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000797 const std::string layerName("depwiseConvolution2d");
798 const armnn::TensorInfo inputInfo ({ 1, 5, 5, 3 }, armnn::DataType::Float32);
799 const armnn::TensorInfo outputInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000800
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000801 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
802 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000803
804 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
805 armnn::ConstTensor weights(weightsInfo, weightsData);
806
807 std::vector<int32_t> biasesData = GenerateRandomData<int32_t>(biasesInfo.GetNumElements());
808 armnn::ConstTensor biases(biasesInfo, biasesData);
809
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000810 armnn::DepthwiseConvolution2dDescriptor descriptor;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100811 descriptor.m_PadLeft = 1;
812 descriptor.m_PadRight = 1;
813 descriptor.m_PadTop = 1;
814 descriptor.m_PadBottom = 1;
815 descriptor.m_StrideX = 2;
816 descriptor.m_StrideY = 2;
817 descriptor.m_DilationX = 2;
818 descriptor.m_DilationY = 2;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000819 descriptor.m_BiasEnabled = true;
820 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
821
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000822 armnn::INetworkPtr network = armnn::INetwork::Create();
823 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
824 armnn::IConnectableLayer* const depthwiseConvLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100825 network->AddDepthwiseConvolution2dLayer(descriptor,
826 weights,
827 armnn::Optional<armnn::ConstTensor>(biases),
828 layerName.c_str());
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000829 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
830
831 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000832 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000833
834 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000835 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
836
837 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
838 BOOST_CHECK(deserializedNetwork);
839
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000840 DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
841 deserializedNetwork->Accept(verifier);
Jim Flynn18ce3382019-03-08 11:08:30 +0000842}
843
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000844BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2dWithPerAxisParams)
845{
846 using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
847 class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
848 {
849 public:
850 DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
851 const std::vector<armnn::TensorInfo>& inputInfos,
852 const std::vector<armnn::TensorInfo>& outputInfos,
853 const Descriptor& descriptor,
854 const armnn::ConstTensor& weights,
855 const armnn::Optional<armnn::ConstTensor>& biases) :
856 LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
857 m_Weights(weights),
858 m_Biases(biases) {}
859
860 void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
861 const Descriptor& descriptor,
862 const armnn::ConstTensor& weights,
863 const armnn::Optional<armnn::ConstTensor>& biases,
864 const char* name) override
865 {
866 VerifyNameAndConnections(layer, name);
867 VerifyDescriptor(descriptor);
868
869 // check weights
870 CompareConstTensor(weights, m_Weights);
871
872 // check biases
873 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
874 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
875
876 if (biases.has_value() && m_Biases.has_value())
877 {
878 CompareConstTensor(biases.value(), m_Biases.value());
879 }
880 }
881
882 private:
883 armnn::ConstTensor m_Weights;
884 armnn::Optional<armnn::ConstTensor> m_Biases;
885 };
886
887 using namespace armnn;
888
889 const std::string layerName("depwiseConvolution2dWithPerAxis");
890 const TensorInfo inputInfo ({ 1, 3, 3, 2 }, DataType::QAsymmU8, 0.55f, 128);
891 const TensorInfo outputInfo({ 1, 2, 2, 4 }, DataType::QAsymmU8, 0.75f, 128);
892
893 const std::vector<float> quantScales{ 0.75f, 0.80f, 0.90f, 0.95f };
894 const unsigned int quantDimension = 0;
895 TensorInfo kernelInfo({ 2, 2, 2, 2 }, DataType::QSymmS8, quantScales, quantDimension);
896
897 const std::vector<float> biasQuantScales{ 0.25f, 0.35f, 0.45f, 0.55f };
898 constexpr unsigned int biasQuantDimension = 0;
899 TensorInfo biasInfo({ 4 }, DataType::Signed32, biasQuantScales, biasQuantDimension);
900
901 std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
902 armnn::ConstTensor weights(kernelInfo, kernelData);
903 std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
904 armnn::ConstTensor biases(biasInfo, biasData);
905
906 DepthwiseConvolution2dDescriptor descriptor;
907 descriptor.m_StrideX = 1;
908 descriptor.m_StrideY = 1;
909 descriptor.m_PadLeft = 0;
910 descriptor.m_PadRight = 0;
911 descriptor.m_PadTop = 0;
912 descriptor.m_PadBottom = 0;
913 descriptor.m_DilationX = 1;
914 descriptor.m_DilationY = 1;
915 descriptor.m_BiasEnabled = true;
916 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
917
918 armnn::INetworkPtr network = armnn::INetwork::Create();
919 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
920 armnn::IConnectableLayer* const depthwiseConvLayer =
921 network->AddDepthwiseConvolution2dLayer(descriptor,
922 weights,
923 armnn::Optional<armnn::ConstTensor>(biases),
924 layerName.c_str());
925 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
926
927 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
928 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
929
930 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
931 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
932
933 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
934 BOOST_CHECK(deserializedNetwork);
935
936 DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
937 deserializedNetwork->Accept(verifier);
938}
939
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000940BOOST_AUTO_TEST_CASE(SerializeDequantize)
941{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100942 DECLARE_LAYER_VERIFIER_CLASS(Dequantize)
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000943
944 const std::string layerName("dequantize");
Derek Lambertif90c56d2020-01-10 17:14:08 +0000945 const armnn::TensorInfo inputInfo({ 1, 5, 2, 3 }, armnn::DataType::QAsymmU8, 0.5f, 1);
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000946 const armnn::TensorInfo outputInfo({ 1, 5, 2, 3 }, armnn::DataType::Float32);
947
948 armnn::INetworkPtr network = armnn::INetwork::Create();
949 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
950 armnn::IConnectableLayer* const dequantizeLayer = network->AddDequantizeLayer(layerName.c_str());
951 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
952
953 inputLayer->GetOutputSlot(0).Connect(dequantizeLayer->GetInputSlot(0));
954 dequantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
955
956 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
957 dequantizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
958
959 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
960 BOOST_CHECK(deserializedNetwork);
961
962 DequantizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
963 deserializedNetwork->Accept(verifier);
964}
965
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000966BOOST_AUTO_TEST_CASE(SerializeDeserializeDetectionPostProcess)
967{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100968 using Descriptor = armnn::DetectionPostProcessDescriptor;
969 class DetectionPostProcessLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000970 {
971 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000972 DetectionPostProcessLayerVerifier(const std::string& layerName,
973 const std::vector<armnn::TensorInfo>& inputInfos,
974 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100975 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000976 const armnn::ConstTensor& anchors)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100977 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
978 , m_Anchors(anchors) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000979
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000980 void VisitDetectionPostProcessLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100981 const Descriptor& descriptor,
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000982 const armnn::ConstTensor& anchors,
983 const char* name) override
984 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000985 VerifyNameAndConnections(layer, name);
986 VerifyDescriptor(descriptor);
987
988 CompareConstTensor(anchors, m_Anchors);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000989 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000990
991 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000992 armnn::ConstTensor m_Anchors;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000993 };
994
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000995 const std::string layerName("detectionPostProcess");
996
997 const std::vector<armnn::TensorInfo> inputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000998 armnn::TensorInfo({ 1, 6, 4 }, armnn::DataType::Float32),
999 armnn::TensorInfo({ 1, 6, 3}, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001000 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001001
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001002 const std::vector<armnn::TensorInfo> outputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001003 armnn::TensorInfo({ 1, 3, 4 }, armnn::DataType::Float32),
1004 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1005 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1006 armnn::TensorInfo({ 1 }, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001007 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001008
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001009 armnn::DetectionPostProcessDescriptor descriptor;
1010 descriptor.m_UseRegularNms = true;
1011 descriptor.m_MaxDetections = 3;
1012 descriptor.m_MaxClassesPerDetection = 1;
1013 descriptor.m_DetectionsPerClass =1;
1014 descriptor.m_NmsScoreThreshold = 0.0;
1015 descriptor.m_NmsIouThreshold = 0.5;
1016 descriptor.m_NumClasses = 2;
1017 descriptor.m_ScaleY = 10.0;
1018 descriptor.m_ScaleX = 10.0;
1019 descriptor.m_ScaleH = 5.0;
1020 descriptor.m_ScaleW = 5.0;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001021
1022 const armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32);
1023 const std::vector<float> anchorsData({
1024 0.5f, 0.5f, 1.0f, 1.0f,
1025 0.5f, 0.5f, 1.0f, 1.0f,
1026 0.5f, 0.5f, 1.0f, 1.0f,
1027 0.5f, 10.5f, 1.0f, 1.0f,
1028 0.5f, 10.5f, 1.0f, 1.0f,
1029 0.5f, 100.5f, 1.0f, 1.0f
1030 });
1031 armnn::ConstTensor anchors(anchorsInfo, anchorsData);
1032
1033 armnn::INetworkPtr network = armnn::INetwork::Create();
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001034 armnn::IConnectableLayer* const detectionLayer =
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001035 network->AddDetectionPostProcessLayer(descriptor, anchors, layerName.c_str());
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001036
1037 for (unsigned int i = 0; i < 2; i++)
1038 {
1039 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(static_cast<int>(i));
1040 inputLayer->GetOutputSlot(0).Connect(detectionLayer->GetInputSlot(i));
1041 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfos[i]);
1042 }
1043
1044 for (unsigned int i = 0; i < 4; i++)
1045 {
1046 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(static_cast<int>(i));
1047 detectionLayer->GetOutputSlot(i).Connect(outputLayer->GetInputSlot(0));
1048 detectionLayer->GetOutputSlot(i).SetTensorInfo(outputInfos[i]);
1049 }
1050
1051 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1052 BOOST_CHECK(deserializedNetwork);
1053
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001054 DetectionPostProcessLayerVerifier verifier(layerName, inputInfos, outputInfos, descriptor, anchors);
1055 deserializedNetwork->Accept(verifier);
1056}
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001057
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001058BOOST_AUTO_TEST_CASE(SerializeDivision)
1059{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001060 DECLARE_LAYER_VERIFIER_CLASS(Division)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001061
1062 const std::string layerName("division");
1063 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1064
1065 armnn::INetworkPtr network = armnn::INetwork::Create();
1066 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1067 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1068 armnn::IConnectableLayer* const divisionLayer = network->AddDivisionLayer(layerName.c_str());
1069 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1070
1071 inputLayer0->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(0));
1072 inputLayer1->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(1));
1073 divisionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1074
1075 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1076 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1077 divisionLayer->GetOutputSlot(0).SetTensorInfo(info);
1078
1079 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1080 BOOST_CHECK(deserializedNetwork);
1081
1082 DivisionLayerVerifier verifier(layerName, {info, info}, {info});
1083 deserializedNetwork->Accept(verifier);
1084}
1085
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001086class EqualLayerVerifier : public LayerVerifierBase
1087{
1088public:
1089 EqualLayerVerifier(const std::string& layerName,
1090 const std::vector<armnn::TensorInfo>& inputInfos,
1091 const std::vector<armnn::TensorInfo>& outputInfos)
1092 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1093
1094 void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1095 const armnn::ComparisonDescriptor& descriptor,
1096 const char* name) override
1097 {
1098 VerifyNameAndConnections(layer, name);
1099 BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Equal);
1100 }
1101
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001102 void VisitEqualLayer(const armnn::IConnectableLayer*, const char*) override
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001103 {
1104 throw armnn::Exception("EqualLayer should have translated to ComparisonLayer");
1105 }
1106};
1107
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001108// NOTE: Until the deprecated AddEqualLayer disappears this test checks that calling
1109// AddEqualLayer places a ComparisonLayer into the serialized format and that
1110// when this deserialises we have a ComparisonLayer
1111BOOST_AUTO_TEST_CASE(SerializeEqual)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001112{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001113 const std::string layerName("equal");
1114
1115 const armnn::TensorShape shape{2, 1, 2, 4};
1116
1117 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1118 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1119
1120 armnn::INetworkPtr network = armnn::INetwork::Create();
1121 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1122 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1123 ARMNN_NO_DEPRECATE_WARN_BEGIN
1124 armnn::IConnectableLayer* const equalLayer = network->AddEqualLayer(layerName.c_str());
1125 ARMNN_NO_DEPRECATE_WARN_END
1126 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1127
1128 inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1129 inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1130 equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1131
1132 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1133 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1134 equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1135
1136 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1137 BOOST_CHECK(deserializedNetwork);
1138
1139 EqualLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1140 deserializedNetwork->Accept(verifier);
1141}
1142
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001143BOOST_AUTO_TEST_CASE(EnsureEqualBackwardCompatibility)
1144{
1145 // The hex data below is a flat buffer containing a simple network with two inputs,
1146 // an EqualLayer (now deprecated) and an output
1147 //
1148 // This test verifies that we can still deserialize this old-style model by replacing
1149 // the EqualLayer with an equivalent ComparisonLayer
1150 const std::vector<uint8_t> equalModel =
1151 {
1152 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1153 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1154 0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1156 0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1157 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1158 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1160 0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1161 0x00, 0x13, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1162 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1163 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1164 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1165 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1166 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
1167 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1168 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1169 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1170 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1171 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1172 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1173 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1174 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1176 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1177 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1178 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
1179 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1180 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1181 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1182 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1183 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1184 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1185 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1186 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1187 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1188 0x04, 0x00, 0x00, 0x00
1189 };
1190
1191 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(equalModel.begin(), equalModel.end()));
1192 BOOST_CHECK(deserializedNetwork);
1193
1194 const armnn::TensorShape shape{ 2, 1, 2, 4 };
1195
1196 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1197 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1198
1199 EqualLayerVerifier verifier("equal", { inputInfo, inputInfo }, { outputInfo });
1200 deserializedNetwork->Accept(verifier);
1201}
1202
Keith Davis300ad562020-06-04 16:34:23 +01001203BOOST_AUTO_TEST_CASE(SerializeFill)
1204{
1205 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Fill)
1206
1207 const std::string layerName("fill");
Teresa Charlin4b10fef2020-07-29 09:36:41 +01001208 const armnn::TensorInfo inputInfo({4}, armnn::DataType::Signed32);
Keith Davis300ad562020-06-04 16:34:23 +01001209 const armnn::TensorInfo outputInfo({1, 3, 3, 1}, armnn::DataType::Float32);
1210
1211 armnn::FillDescriptor descriptor(1.0f);
1212
1213 armnn::INetworkPtr network = armnn::INetwork::Create();
1214 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1215 armnn::IConnectableLayer* const fillLayer = network->AddFillLayer(descriptor, layerName.c_str());
1216 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1217
1218 inputLayer->GetOutputSlot(0).Connect(fillLayer->GetInputSlot(0));
1219 fillLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1220
1221 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1222 fillLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1223
1224 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1225 BOOST_CHECK(deserializedNetwork);
1226
1227 FillLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1228
1229 deserializedNetwork->Accept(verifier);
1230}
1231
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001232BOOST_AUTO_TEST_CASE(SerializeFloor)
1233{
1234 DECLARE_LAYER_VERIFIER_CLASS(Floor)
1235
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001236 const std::string layerName("floor");
1237 const armnn::TensorInfo info({4,4}, armnn::DataType::Float32);
1238
1239 armnn::INetworkPtr network = armnn::INetwork::Create();
1240 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1241 armnn::IConnectableLayer* const floorLayer = network->AddFloorLayer(layerName.c_str());
1242 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1243
1244 inputLayer->GetOutputSlot(0).Connect(floorLayer->GetInputSlot(0));
1245 floorLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1246
1247 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1248 floorLayer->GetOutputSlot(0).SetTensorInfo(info);
1249
1250 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1251 BOOST_CHECK(deserializedNetwork);
1252
1253 FloorLayerVerifier verifier(layerName, {info}, {info});
1254 deserializedNetwork->Accept(verifier);
1255}
1256
1257BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
1258{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001259 using Descriptor = armnn::FullyConnectedDescriptor;
1260 class FullyConnectedLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001261 {
1262 public:
1263 FullyConnectedLayerVerifier(const std::string& layerName,
1264 const std::vector<armnn::TensorInfo>& inputInfos,
1265 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001266 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001267 const armnn::ConstTensor& weight,
1268 const armnn::Optional<armnn::ConstTensor>& bias)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001269 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
1270 , m_Weight(weight)
1271 , m_Bias(bias) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001272
1273 void VisitFullyConnectedLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001274 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001275 const armnn::ConstTensor& weight,
1276 const armnn::Optional<armnn::ConstTensor>& bias,
1277 const char* name) override
1278 {
1279 VerifyNameAndConnections(layer, name);
1280 VerifyDescriptor(descriptor);
1281
1282 CompareConstTensor(weight, m_Weight);
1283
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001284 BOOST_TEST(bias.has_value() == descriptor.m_BiasEnabled);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001285 BOOST_TEST(bias.has_value() == m_Bias.has_value());
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001286
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001287 if (bias.has_value() && m_Bias.has_value())
1288 {
1289 CompareConstTensor(bias.value(), m_Bias.value());
1290 }
1291 }
1292
1293 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001294 armnn::ConstTensor m_Weight;
1295 armnn::Optional<armnn::ConstTensor> m_Bias;
1296 };
1297
1298 const std::string layerName("fullyConnected");
1299 const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
1300 const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
1301
1302 const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
1303 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
1304 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
1305 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
1306 armnn::ConstTensor weights(weightsInfo, weightsData);
1307 armnn::ConstTensor biases(biasesInfo, biasesData);
1308
1309 armnn::FullyConnectedDescriptor descriptor;
1310 descriptor.m_BiasEnabled = true;
1311 descriptor.m_TransposeWeightMatrix = false;
1312
1313 armnn::INetworkPtr network = armnn::INetwork::Create();
1314 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1315 armnn::IConnectableLayer* const fullyConnectedLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +01001316 network->AddFullyConnectedLayer(descriptor,
1317 weights,
1318 armnn::Optional<armnn::ConstTensor>(biases),
1319 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001320 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1321
1322 inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
1323 fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1324
1325 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1326 fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1327
1328 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1329 BOOST_CHECK(deserializedNetwork);
1330
1331 FullyConnectedLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
1332 deserializedNetwork->Accept(verifier);
1333}
1334
1335BOOST_AUTO_TEST_CASE(SerializeGather)
1336{
Teresa Charlin52664732020-06-29 16:27:03 +01001337 using GatherDescriptor = armnn::GatherDescriptor;
1338 class GatherLayerVerifier : public LayerVerifierBaseWithDescriptor<GatherDescriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001339 {
1340 public:
1341 GatherLayerVerifier(const std::string& layerName,
1342 const std::vector<armnn::TensorInfo>& inputInfos,
Teresa Charlin52664732020-06-29 16:27:03 +01001343 const std::vector<armnn::TensorInfo>& outputInfos,
1344 const GatherDescriptor& descriptor)
1345 : LayerVerifierBaseWithDescriptor<GatherDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001346
Teresa Charlin52664732020-06-29 16:27:03 +01001347 void VisitGatherLayer(const armnn::IConnectableLayer* layer,
1348 const GatherDescriptor& descriptor,
1349 const char *name) override
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001350 {
1351 VerifyNameAndConnections(layer, name);
Teresa Charlin52664732020-06-29 16:27:03 +01001352 BOOST_CHECK(descriptor.m_Axis == m_Descriptor.m_Axis);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001353 }
1354
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001355 void VisitConstantLayer(const armnn::IConnectableLayer*,
1356 const armnn::ConstTensor&,
1357 const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001358 };
1359
1360 const std::string layerName("gather");
Derek Lambertif90c56d2020-01-10 17:14:08 +00001361 armnn::TensorInfo paramsInfo({ 8 }, armnn::DataType::QAsymmU8);
1362 armnn::TensorInfo outputInfo({ 3 }, armnn::DataType::QAsymmU8);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001363 const armnn::TensorInfo indicesInfo({ 3 }, armnn::DataType::Signed32);
Teresa Charlin52664732020-06-29 16:27:03 +01001364 GatherDescriptor descriptor;
1365 descriptor.m_Axis = 1;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001366
1367 paramsInfo.SetQuantizationScale(1.0f);
1368 paramsInfo.SetQuantizationOffset(0);
1369 outputInfo.SetQuantizationScale(1.0f);
1370 outputInfo.SetQuantizationOffset(0);
1371
1372 const std::vector<int32_t>& indicesData = {7, 6, 5};
1373
1374 armnn::INetworkPtr network = armnn::INetwork::Create();
1375 armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
1376 armnn::IConnectableLayer *const constantLayer =
1377 network->AddConstantLayer(armnn::ConstTensor(indicesInfo, indicesData));
Teresa Charlin52664732020-06-29 16:27:03 +01001378 armnn::IConnectableLayer *const gatherLayer = network->AddGatherLayer(descriptor, layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001379 armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
1380
1381 inputLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(0));
1382 constantLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(1));
1383 gatherLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1384
1385 inputLayer->GetOutputSlot(0).SetTensorInfo(paramsInfo);
1386 constantLayer->GetOutputSlot(0).SetTensorInfo(indicesInfo);
1387 gatherLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1388
1389 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1390 BOOST_CHECK(deserializedNetwork);
1391
Teresa Charlin52664732020-06-29 16:27:03 +01001392 GatherLayerVerifier verifier(layerName, {paramsInfo, indicesInfo}, {outputInfo}, descriptor);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001393 deserializedNetwork->Accept(verifier);
1394}
1395
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001396class GreaterLayerVerifier : public LayerVerifierBase
1397{
1398public:
1399 GreaterLayerVerifier(const std::string& layerName,
1400 const std::vector<armnn::TensorInfo>& inputInfos,
1401 const std::vector<armnn::TensorInfo>& outputInfos)
1402 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1403
1404 void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1405 const armnn::ComparisonDescriptor& descriptor,
1406 const char* name) override
1407 {
1408 VerifyNameAndConnections(layer, name);
1409 BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Greater);
1410 }
1411
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001412 void VisitGreaterLayer(const armnn::IConnectableLayer*, const char*) override
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001413 {
1414 throw armnn::Exception("GreaterLayer should have translated to ComparisonLayer");
1415 }
1416};
1417
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001418// NOTE: Until the deprecated AddGreaterLayer disappears this test checks that calling
1419// AddGreaterLayer places a ComparisonLayer into the serialized format and that
1420// when this deserialises we have a ComparisonLayer
1421BOOST_AUTO_TEST_CASE(SerializeGreater)
Aron Virginas-Tar781ced92019-10-03 11:15:39 +01001422{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001423 const std::string layerName("greater");
1424
1425 const armnn::TensorShape shape{2, 1, 2, 4};
1426
1427 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1428 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1429
1430 armnn::INetworkPtr network = armnn::INetwork::Create();
1431 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1432 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1433 ARMNN_NO_DEPRECATE_WARN_BEGIN
1434 armnn::IConnectableLayer* const equalLayer = network->AddGreaterLayer(layerName.c_str());
1435 ARMNN_NO_DEPRECATE_WARN_END
1436 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1437
1438 inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1439 inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1440 equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1441
1442 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1443 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1444 equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1445
1446 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1447 BOOST_CHECK(deserializedNetwork);
1448
1449 GreaterLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1450 deserializedNetwork->Accept(verifier);
1451}
1452
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001453BOOST_AUTO_TEST_CASE(EnsureGreaterBackwardCompatibility)
1454{
1455 // The hex data below is a flat buffer containing a simple network with two inputs,
1456 // an GreaterLayer (now deprecated) and an output
1457 //
1458 // This test verifies that we can still deserialize this old-style model by replacing
1459 // the GreaterLayer with an equivalent ComparisonLayer
1460 const std::vector<uint8_t> greaterModel =
1461 {
1462 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1463 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1464 0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1466 0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1467 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1468 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1469 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1470 0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1471 0x00, 0x19, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1472 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1473 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x00, 0x02, 0x00, 0x00, 0x00,
1474 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1475 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1476 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1477 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1478 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1479 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1480 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1481 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1482 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1483 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1484 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1486 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1487 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1488 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1489 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1490 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1491 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1492 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1493 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1494 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1495 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1496 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1497 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1498 0x02, 0x00, 0x00, 0x00
1499 };
1500
1501 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(greaterModel.begin(), greaterModel.end()));
1502 BOOST_CHECK(deserializedNetwork);
1503
1504 const armnn::TensorShape shape{ 1, 2, 2, 2 };
1505
1506 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1507 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1508
1509 GreaterLayerVerifier verifier("greater", { inputInfo, inputInfo }, { outputInfo });
1510 deserializedNetwork->Accept(verifier);
1511}
1512
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001513BOOST_AUTO_TEST_CASE(SerializeInstanceNormalization)
1514{
1515 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(InstanceNormalization)
1516
Aron Virginas-Tar781ced92019-10-03 11:15:39 +01001517 const std::string layerName("instanceNormalization");
1518 const armnn::TensorInfo info({ 1, 2, 1, 5 }, armnn::DataType::Float32);
1519
1520 armnn::InstanceNormalizationDescriptor descriptor;
1521 descriptor.m_Gamma = 1.1f;
1522 descriptor.m_Beta = 0.1f;
1523 descriptor.m_Eps = 0.0001f;
1524 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
1525
1526 armnn::INetworkPtr network = armnn::INetwork::Create();
1527 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1528 armnn::IConnectableLayer* const instanceNormLayer =
1529 network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1530 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1531
1532 inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1533 instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1534
1535 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1536 instanceNormLayer->GetOutputSlot(0).SetTensorInfo(info);
1537
1538 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1539 BOOST_CHECK(deserializedNetwork);
1540
1541 InstanceNormalizationLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1542 deserializedNetwork->Accept(verifier);
1543}
1544
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001545DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(L2Normalization)
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001546
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001547BOOST_AUTO_TEST_CASE(SerializeL2Normalization)
1548{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001549 const std::string l2NormLayerName("l2Normalization");
1550 const armnn::TensorInfo info({1, 2, 1, 5}, armnn::DataType::Float32);
1551
1552 armnn::L2NormalizationDescriptor desc;
1553 desc.m_DataLayout = armnn::DataLayout::NCHW;
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001554 desc.m_Eps = 0.0001f;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001555
1556 armnn::INetworkPtr network = armnn::INetwork::Create();
1557 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1558 armnn::IConnectableLayer* const l2NormLayer = network->AddL2NormalizationLayer(desc, l2NormLayerName.c_str());
1559 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1560
1561 inputLayer0->GetOutputSlot(0).Connect(l2NormLayer->GetInputSlot(0));
1562 l2NormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1563
1564 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1565 l2NormLayer->GetOutputSlot(0).SetTensorInfo(info);
1566
1567 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1568 BOOST_CHECK(deserializedNetwork);
1569
1570 L2NormalizationLayerVerifier verifier(l2NormLayerName, {info}, {info}, desc);
1571 deserializedNetwork->Accept(verifier);
1572}
1573
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001574BOOST_AUTO_TEST_CASE(EnsureL2NormalizationBackwardCompatibility)
1575{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001576 // The hex data below is a flat buffer containing a simple network with one input
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001577 // a L2Normalization layer and an output layer with dimensions as per the tensor infos below.
1578 //
1579 // This test verifies that we can still read back these old style
1580 // models without the normalization epsilon value.
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001581 const std::vector<uint8_t> l2NormalizationModel =
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001582 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001583 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1584 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1585 0x3C, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1586 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
1587 0x04, 0x00, 0x00, 0x00, 0xD6, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
1588 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
1589 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1591 0x4C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1592 0x00, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1593 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1594 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1595 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x20, 0x00,
1596 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x6C, 0x32, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x61, 0x74,
1597 0x69, 0x6F, 0x6E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00,
1598 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1599 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
1600 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1601 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1602 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1603 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1604 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1605 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1606 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1607 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1608 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1609 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1610 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1611 0x05, 0x00, 0x00, 0x00, 0x00
1612 };
1613
1614 armnn::INetworkPtr deserializedNetwork =
1615 DeserializeNetwork(std::string(l2NormalizationModel.begin(), l2NormalizationModel.end()));
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001616 BOOST_CHECK(deserializedNetwork);
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001617
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001618 const std::string layerName("l2Normalization");
1619 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 2, 1, 5}, armnn::DataType::Float32);
1620
1621 armnn::L2NormalizationDescriptor desc;
1622 desc.m_DataLayout = armnn::DataLayout::NCHW;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001623 // Since this variable does not exist in the l2NormalizationModel dump, the default value will be loaded
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001624 desc.m_Eps = 1e-12f;
1625
1626 L2NormalizationLayerVerifier verifier(layerName, {inputInfo}, {inputInfo}, desc);
1627 deserializedNetwork->Accept(verifier);
1628}
1629
James Conroyaba90cd2020-11-06 16:28:18 +00001630BOOST_AUTO_TEST_CASE(SerializeLogicalBinary)
1631{
1632 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(LogicalBinary)
1633
1634 const std::string layerName("logicalBinaryAnd");
1635
1636 const armnn::TensorShape shape{2, 1, 2, 2};
1637
1638 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1639 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1640
1641 armnn::LogicalBinaryDescriptor descriptor(armnn::LogicalBinaryOperation::LogicalAnd);
1642
1643 armnn::INetworkPtr network = armnn::INetwork::Create();
1644 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1645 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1646 armnn::IConnectableLayer* const logicalBinaryLayer = network->AddLogicalBinaryLayer(descriptor, layerName.c_str());
1647 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1648
1649 inputLayer0->GetOutputSlot(0).Connect(logicalBinaryLayer->GetInputSlot(0));
1650 inputLayer1->GetOutputSlot(0).Connect(logicalBinaryLayer->GetInputSlot(1));
1651 logicalBinaryLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1652
1653 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1654 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1655 logicalBinaryLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1656
1657 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1658 BOOST_CHECK(deserializedNetwork);
1659
1660 LogicalBinaryLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo }, descriptor);
1661 deserializedNetwork->Accept(verifier);
1662}
1663
1664BOOST_AUTO_TEST_CASE(SerializeLogicalUnary)
1665{
1666 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(ElementwiseUnary)
1667
1668 const std::string layerName("elementwiseUnaryLogicalNot");
1669
1670 const armnn::TensorShape shape{2, 1, 2, 2};
1671
1672 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1673 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1674
1675 armnn::ElementwiseUnaryDescriptor descriptor(armnn::UnaryOperation::LogicalNot);
1676
1677 armnn::INetworkPtr network = armnn::INetwork::Create();
1678 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1679 armnn::IConnectableLayer* const elementwiseUnaryLayer =
1680 network->AddElementwiseUnaryLayer(descriptor, layerName.c_str());
1681 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1682
1683 inputLayer->GetOutputSlot(0).Connect(elementwiseUnaryLayer->GetInputSlot(0));
1684 elementwiseUnaryLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1685
1686 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1687 elementwiseUnaryLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1688
1689 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1690
1691 BOOST_CHECK(deserializedNetwork);
1692
1693 ElementwiseUnaryLayerVerifier verifier(layerName, { inputInfo }, { outputInfo }, descriptor);
1694
1695 deserializedNetwork->Accept(verifier);
1696}
1697
Sadik Armagan26257852019-10-14 13:00:47 +01001698BOOST_AUTO_TEST_CASE(SerializeLogSoftmax)
1699{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001700 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(LogSoftmax)
Sadik Armagan26257852019-10-14 13:00:47 +01001701
1702 const std::string layerName("log_softmax");
1703 const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
1704
1705 armnn::LogSoftmaxDescriptor descriptor;
1706 descriptor.m_Beta = 1.0f;
1707 descriptor.m_Axis = -1;
1708
1709 armnn::INetworkPtr network = armnn::INetwork::Create();
1710 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1711 armnn::IConnectableLayer* const logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
1712 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1713
1714 inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
1715 logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1716
1717 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1718 logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
1719
1720 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1721 BOOST_CHECK(deserializedNetwork);
1722
1723 LogSoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1724 deserializedNetwork->Accept(verifier);
1725}
1726
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001727BOOST_AUTO_TEST_CASE(SerializeMaximum)
1728{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001729 DECLARE_LAYER_VERIFIER_CLASS(Maximum)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001730
1731 const std::string layerName("maximum");
1732 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1733
1734 armnn::INetworkPtr network = armnn::INetwork::Create();
1735 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1736 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1737 armnn::IConnectableLayer* const maximumLayer = network->AddMaximumLayer(layerName.c_str());
1738 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1739
1740 inputLayer0->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(0));
1741 inputLayer1->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(1));
1742 maximumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1743
1744 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1745 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1746 maximumLayer->GetOutputSlot(0).SetTensorInfo(info);
1747
1748 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1749 BOOST_CHECK(deserializedNetwork);
1750
1751 MaximumLayerVerifier verifier(layerName, {info, info}, {info});
1752 deserializedNetwork->Accept(verifier);
1753}
1754
1755BOOST_AUTO_TEST_CASE(SerializeMean)
1756{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001757 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Mean)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001758
1759 const std::string layerName("mean");
1760 const armnn::TensorInfo inputInfo({1, 1, 3, 2}, armnn::DataType::Float32);
1761 const armnn::TensorInfo outputInfo({1, 1, 1, 2}, armnn::DataType::Float32);
1762
1763 armnn::MeanDescriptor descriptor;
1764 descriptor.m_Axis = { 2 };
1765 descriptor.m_KeepDims = true;
1766
1767 armnn::INetworkPtr network = armnn::INetwork::Create();
1768 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1769 armnn::IConnectableLayer* const meanLayer = network->AddMeanLayer(descriptor, layerName.c_str());
1770 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1771
1772 inputLayer->GetOutputSlot(0).Connect(meanLayer->GetInputSlot(0));
1773 meanLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1774
1775 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1776 meanLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1777
1778 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1779 BOOST_CHECK(deserializedNetwork);
1780
1781 MeanLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1782 deserializedNetwork->Accept(verifier);
1783}
1784
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001785BOOST_AUTO_TEST_CASE(SerializeMerge)
1786{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001787 DECLARE_LAYER_VERIFIER_CLASS(Merge)
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001788
1789 const std::string layerName("merge");
1790 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1791
1792 armnn::INetworkPtr network = armnn::INetwork::Create();
1793 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1794 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1795 armnn::IConnectableLayer* const mergeLayer = network->AddMergeLayer(layerName.c_str());
1796 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1797
1798 inputLayer0->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(0));
1799 inputLayer1->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(1));
1800 mergeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1801
1802 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1803 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1804 mergeLayer->GetOutputSlot(0).SetTensorInfo(info);
1805
1806 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1807 BOOST_CHECK(deserializedNetwork);
1808
1809 MergeLayerVerifier verifier(layerName, {info, info}, {info});
1810 deserializedNetwork->Accept(verifier);
1811}
1812
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001813class MergerLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001814{
Jim Flynn5fa83932019-05-09 15:35:43 +01001815public:
1816 MergerLayerVerifier(const std::string& layerName,
1817 const std::vector<armnn::TensorInfo>& inputInfos,
1818 const std::vector<armnn::TensorInfo>& outputInfos,
1819 const armnn::OriginsDescriptor& descriptor)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001820 : LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001821
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001822 void VisitMergerLayer(const armnn::IConnectableLayer*,
1823 const armnn::OriginsDescriptor&,
1824 const char*) override
Jim Flynn5fa83932019-05-09 15:35:43 +01001825 {
Jim Flynne242f2d2019-05-22 14:24:13 +01001826 throw armnn::Exception("MergerLayer should have translated to ConcatLayer");
1827 }
1828
1829 void VisitConcatLayer(const armnn::IConnectableLayer* layer,
1830 const armnn::OriginsDescriptor& descriptor,
1831 const char* name) override
1832 {
Jim Flynn5fa83932019-05-09 15:35:43 +01001833 VerifyNameAndConnections(layer, name);
1834 VerifyDescriptor(descriptor);
1835 }
Jim Flynn5fa83932019-05-09 15:35:43 +01001836};
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001837
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001838// NOTE: Until the deprecated AddMergerLayer disappears this test checks that calling
Jim Flynne242f2d2019-05-22 14:24:13 +01001839// AddMergerLayer places a ConcatLayer into the serialized format and that
1840// when this deserialises we have a ConcatLayer
Jim Flynn5fa83932019-05-09 15:35:43 +01001841BOOST_AUTO_TEST_CASE(SerializeMerger)
1842{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001843 const std::string layerName("merger");
1844 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1845 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1846
1847 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1848
1849 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001850 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001851
1852 armnn::INetworkPtr network = armnn::INetwork::Create();
1853 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1854 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
Jim Flynn906f9462019-05-10 13:55:21 +01001855 ARMNN_NO_DEPRECATE_WARN_BEGIN
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001856 armnn::IConnectableLayer* const mergerLayer = network->AddMergerLayer(descriptor, layerName.c_str());
Jim Flynn906f9462019-05-10 13:55:21 +01001857 ARMNN_NO_DEPRECATE_WARN_END
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001858 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1859
1860 inputLayerOne->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0));
1861 inputLayerTwo->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1));
1862 mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1863
1864 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1865 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1866 mergerLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1867
Jim Flynn5fa83932019-05-09 15:35:43 +01001868 std::string mergerLayerNetwork = SerializeNetwork(*network);
1869 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(mergerLayerNetwork);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001870 BOOST_CHECK(deserializedNetwork);
1871
1872 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1873 deserializedNetwork->Accept(verifier);
1874}
1875
Jim Flynn5fa83932019-05-09 15:35:43 +01001876BOOST_AUTO_TEST_CASE(EnsureMergerLayerBackwardCompatibility)
1877{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001878 // The hex data below is a flat buffer containing a simple network with two inputs
Jim Flynne242f2d2019-05-22 14:24:13 +01001879 // a merger layer (now deprecated) and an output layer with dimensions as per the tensor infos below.
1880 //
1881 // This test verifies that we can still read back these old style
Jim Flynn5fa83932019-05-09 15:35:43 +01001882 // models replacing the MergerLayers with ConcatLayers with the same parameters.
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001883 const std::vector<uint8_t> mergerModel =
Jim Flynn5fa83932019-05-09 15:35:43 +01001884 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001885 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1886 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1887 0x38, 0x02, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1889 0xF4, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1890 0x00, 0x00, 0x9A, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1891 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1892 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1893 0xF8, 0xFE, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1894 0x00, 0x1F, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1895 0x68, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
1896 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1897 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
1898 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1899 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1900 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1901 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1902 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x72, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1903 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1904 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
1905 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00,
1906 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1907 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1908 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1909 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1910 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1911 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1912 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1913 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1915 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1916 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1917 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1918 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1919 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1920 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1921 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1922 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1923 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1924 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1925 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1926 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1927 0x02, 0x00, 0x00, 0x00
1928 };
1929
1930 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(mergerModel.begin(), mergerModel.end()));
Jim Flynn5fa83932019-05-09 15:35:43 +01001931 BOOST_CHECK(deserializedNetwork);
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001932
1933 const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 2, 3, 2, 2 }, armnn::DataType::Float32);
1934 const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 4, 3, 2, 2 }, armnn::DataType::Float32);
Jim Flynn5fa83932019-05-09 15:35:43 +01001935
1936 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1937
1938 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001939 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Jim Flynn5fa83932019-05-09 15:35:43 +01001940
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001941 MergerLayerVerifier verifier("merger", { inputInfo, inputInfo }, { outputInfo }, descriptor);
Jim Flynn5fa83932019-05-09 15:35:43 +01001942 deserializedNetwork->Accept(verifier);
1943}
1944
Jim Flynne242f2d2019-05-22 14:24:13 +01001945BOOST_AUTO_TEST_CASE(SerializeConcat)
1946{
1947 const std::string layerName("concat");
1948 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1949 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1950
1951 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1952
1953 armnn::OriginsDescriptor descriptor =
1954 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1955
1956 armnn::INetworkPtr network = armnn::INetwork::Create();
1957 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1958 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1959 armnn::IConnectableLayer* const concatLayer = network->AddConcatLayer(descriptor, layerName.c_str());
1960 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1961
1962 inputLayerOne->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
1963 inputLayerTwo->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
1964 concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1965
1966 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1967 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1968 concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1969
1970 std::string concatLayerNetwork = SerializeNetwork(*network);
1971 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(concatLayerNetwork);
1972 BOOST_CHECK(deserializedNetwork);
1973
1974 // NOTE: using the MergerLayerVerifier to ensure that it is a concat layer and not a
1975 // merger layer that gets placed into the graph.
1976 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1977 deserializedNetwork->Accept(verifier);
1978}
1979
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001980BOOST_AUTO_TEST_CASE(SerializeMinimum)
1981{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001982 DECLARE_LAYER_VERIFIER_CLASS(Minimum)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001983
1984 const std::string layerName("minimum");
1985 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1986
1987 armnn::INetworkPtr network = armnn::INetwork::Create();
1988 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1989 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1990 armnn::IConnectableLayer* const minimumLayer = network->AddMinimumLayer(layerName.c_str());
1991 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1992
1993 inputLayer0->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(0));
1994 inputLayer1->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(1));
1995 minimumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1996
1997 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1998 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1999 minimumLayer->GetOutputSlot(0).SetTensorInfo(info);
2000
2001 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2002 BOOST_CHECK(deserializedNetwork);
2003
2004 MinimumLayerVerifier verifier(layerName, {info, info}, {info});
2005 deserializedNetwork->Accept(verifier);
2006}
2007
2008BOOST_AUTO_TEST_CASE(SerializeMultiplication)
2009{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002010 DECLARE_LAYER_VERIFIER_CLASS(Multiplication)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002011
2012 const std::string layerName("multiplication");
2013 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
2014
2015 armnn::INetworkPtr network = armnn::INetwork::Create();
2016 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2017 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2018 armnn::IConnectableLayer* const multiplicationLayer = network->AddMultiplicationLayer(layerName.c_str());
2019 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2020
2021 inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(0));
2022 inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(1));
2023 multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2024
2025 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2026 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2027 multiplicationLayer->GetOutputSlot(0).SetTensorInfo(info);
2028
2029 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2030 BOOST_CHECK(deserializedNetwork);
2031
2032 MultiplicationLayerVerifier verifier(layerName, {info, info}, {info});
2033 deserializedNetwork->Accept(verifier);
2034}
2035
Ellen Norris-Thompson51982472019-06-19 11:46:21 +01002036BOOST_AUTO_TEST_CASE(SerializePrelu)
2037{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002038 DECLARE_LAYER_VERIFIER_CLASS(Prelu)
Ellen Norris-Thompson51982472019-06-19 11:46:21 +01002039
2040 const std::string layerName("prelu");
2041
2042 armnn::TensorInfo inputTensorInfo ({ 4, 1, 2 }, armnn::DataType::Float32);
2043 armnn::TensorInfo alphaTensorInfo ({ 5, 4, 3, 1 }, armnn::DataType::Float32);
2044 armnn::TensorInfo outputTensorInfo({ 5, 4, 3, 2 }, armnn::DataType::Float32);
2045
2046 armnn::INetworkPtr network = armnn::INetwork::Create();
2047 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2048 armnn::IConnectableLayer* const alphaLayer = network->AddInputLayer(1);
2049 armnn::IConnectableLayer* const preluLayer = network->AddPreluLayer(layerName.c_str());
2050 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2051
2052 inputLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(0));
2053 alphaLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(1));
2054 preluLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2055
2056 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2057 alphaLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
2058 preluLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2059
2060 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2061 BOOST_CHECK(deserializedNetwork);
2062
2063 PreluLayerVerifier verifier(layerName, {inputTensorInfo, alphaTensorInfo}, {outputTensorInfo});
2064 deserializedNetwork->Accept(verifier);
2065}
2066
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002067BOOST_AUTO_TEST_CASE(SerializeNormalization)
2068{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002069 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Normalization)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002070
2071 const std::string layerName("normalization");
2072 const armnn::TensorInfo info({2, 1, 2, 2}, armnn::DataType::Float32);
2073
2074 armnn::NormalizationDescriptor desc;
2075 desc.m_DataLayout = armnn::DataLayout::NCHW;
2076 desc.m_NormSize = 3;
2077 desc.m_Alpha = 1;
2078 desc.m_Beta = 1;
2079 desc.m_K = 1;
2080
2081 armnn::INetworkPtr network = armnn::INetwork::Create();
2082 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2083 armnn::IConnectableLayer* const normalizationLayer = network->AddNormalizationLayer(desc, layerName.c_str());
2084 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2085
2086 inputLayer->GetOutputSlot(0).Connect(normalizationLayer->GetInputSlot(0));
2087 normalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2088
2089 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2090 normalizationLayer->GetOutputSlot(0).SetTensorInfo(info);
2091
2092 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2093 BOOST_CHECK(deserializedNetwork);
2094
2095 NormalizationLayerVerifier verifier(layerName, {info}, {info}, desc);
2096 deserializedNetwork->Accept(verifier);
2097}
2098
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002099DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pad)
Jim Flynn965c7c62019-06-24 14:32:41 +01002100
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002101BOOST_AUTO_TEST_CASE(SerializePad)
2102{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002103 const std::string layerName("pad");
2104 const armnn::TensorInfo inputTensorInfo = armnn::TensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2105 const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({1, 3, 5, 7}, armnn::DataType::Float32);
2106
2107 armnn::PadDescriptor desc({{0, 0}, {1, 0}, {1, 1}, {1, 2}});
2108
2109 armnn::INetworkPtr network = armnn::INetwork::Create();
2110 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2111 armnn::IConnectableLayer* const padLayer = network->AddPadLayer(desc, layerName.c_str());
2112 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2113
2114 inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
2115 padLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2116
2117 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2118 padLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2119
2120 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2121 BOOST_CHECK(deserializedNetwork);
2122
2123 PadLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, desc);
2124 deserializedNetwork->Accept(verifier);
2125}
2126
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002127BOOST_AUTO_TEST_CASE(EnsurePadBackwardCompatibility)
Jim Flynn965c7c62019-06-24 14:32:41 +01002128{
2129 // The PadDescriptor is being extended with a float PadValue (so a value other than 0
2130 // can be used to pad the tensor.
2131 //
2132 // This test contains a binary representation of a simple input->pad->output network
2133 // prior to this change to test that the descriptor has been updated in a backward
2134 // compatible way with respect to Deserialization of older binary dumps
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002135 const std::vector<uint8_t> padModel =
Jim Flynn965c7c62019-06-24 14:32:41 +01002136 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002137 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2138 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2139 0x54, 0x01, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2140 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD0, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2141 0x04, 0x00, 0x00, 0x00, 0x96, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
2142 0x00, 0x00, 0x72, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2143 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
2144 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
2145 0x00, 0x00, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x16, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00,
2146 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2147 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00,
2148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2149 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
2150 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
2151 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00,
2152 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
2153 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
2154 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2155 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2156 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
2157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00,
2158 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00,
2159 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2160 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00,
2161 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2163 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2164 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
2165 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
2166 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00
2167 };
2168
2169 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(padModel.begin(), padModel.end()));
Jim Flynn965c7c62019-06-24 14:32:41 +01002170 BOOST_CHECK(deserializedNetwork);
2171
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002172 const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 1, 2, 3, 4 }, armnn::DataType::Float32);
2173 const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 1, 3, 5, 7 }, armnn::DataType::Float32);
Jim Flynn965c7c62019-06-24 14:32:41 +01002174
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002175 armnn::PadDescriptor descriptor({{ 0, 0 }, { 1, 0 }, { 1, 1 }, { 1, 2 }});
Jim Flynn965c7c62019-06-24 14:32:41 +01002176
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002177 PadLayerVerifier verifier("pad", { inputInfo }, { outputInfo }, descriptor);
Jim Flynn965c7c62019-06-24 14:32:41 +01002178 deserializedNetwork->Accept(verifier);
2179}
2180
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002181BOOST_AUTO_TEST_CASE(SerializePermute)
2182{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002183 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Permute)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002184
2185 const std::string layerName("permute");
2186 const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2187 const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2188
2189 armnn::PermuteDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2190
2191 armnn::INetworkPtr network = armnn::INetwork::Create();
2192 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2193 armnn::IConnectableLayer* const permuteLayer = network->AddPermuteLayer(descriptor, layerName.c_str());
2194 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2195
2196 inputLayer->GetOutputSlot(0).Connect(permuteLayer->GetInputSlot(0));
2197 permuteLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2198
2199 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2200 permuteLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2201
2202 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2203 BOOST_CHECK(deserializedNetwork);
2204
2205 PermuteLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2206 deserializedNetwork->Accept(verifier);
2207}
2208
2209BOOST_AUTO_TEST_CASE(SerializePooling2d)
2210{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002211 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pooling2d)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002212
2213 const std::string layerName("pooling2d");
2214 const armnn::TensorInfo inputInfo({1, 2, 2, 1}, armnn::DataType::Float32);
2215 const armnn::TensorInfo outputInfo({1, 1, 1, 1}, armnn::DataType::Float32);
2216
2217 armnn::Pooling2dDescriptor desc;
2218 desc.m_DataLayout = armnn::DataLayout::NHWC;
2219 desc.m_PadTop = 0;
2220 desc.m_PadBottom = 0;
2221 desc.m_PadLeft = 0;
2222 desc.m_PadRight = 0;
2223 desc.m_PoolType = armnn::PoolingAlgorithm::Average;
2224 desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
2225 desc.m_PaddingMethod = armnn::PaddingMethod::Exclude;
2226 desc.m_PoolHeight = 2;
2227 desc.m_PoolWidth = 2;
2228 desc.m_StrideX = 2;
2229 desc.m_StrideY = 2;
2230
2231 armnn::INetworkPtr network = armnn::INetwork::Create();
2232 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2233 armnn::IConnectableLayer* const pooling2dLayer = network->AddPooling2dLayer(desc, layerName.c_str());
2234 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2235
2236 inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0));
2237 pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2238
2239 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2240 pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2241
2242 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2243 BOOST_CHECK(deserializedNetwork);
2244
2245 Pooling2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2246 deserializedNetwork->Accept(verifier);
2247}
2248
Derek Lamberti87acb272019-03-27 16:51:31 +00002249BOOST_AUTO_TEST_CASE(SerializeQuantize)
2250{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002251 DECLARE_LAYER_VERIFIER_CLASS(Quantize)
Derek Lamberti87acb272019-03-27 16:51:31 +00002252
2253 const std::string layerName("quantize");
2254 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
2255
2256 armnn::INetworkPtr network = armnn::INetwork::Create();
2257 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2258 armnn::IConnectableLayer* const quantizeLayer = network->AddQuantizeLayer(layerName.c_str());
2259 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2260
2261 inputLayer->GetOutputSlot(0).Connect(quantizeLayer->GetInputSlot(0));
2262 quantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2263
2264 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2265 quantizeLayer->GetOutputSlot(0).SetTensorInfo(info);
2266
2267 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2268 BOOST_CHECK(deserializedNetwork);
2269
2270 QuantizeLayerVerifier verifier(layerName, {info}, {info});
2271 deserializedNetwork->Accept(verifier);
2272}
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002273
Finn Williams2605b232020-06-10 15:53:46 +01002274BOOST_AUTO_TEST_CASE(SerializeRank)
2275{
2276 DECLARE_LAYER_VERIFIER_CLASS(Rank)
2277
2278 const std::string layerName("rank");
2279 const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2280 const armnn::TensorInfo outputInfo({1}, armnn::DataType::Signed32);
2281
2282 armnn::INetworkPtr network = armnn::INetwork::Create();
2283 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2284 armnn::IConnectableLayer* const rankLayer = network->AddRankLayer(layerName.c_str());
2285 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2286
2287 inputLayer->GetOutputSlot(0).Connect(rankLayer->GetInputSlot(0));
2288 rankLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2289
2290 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2291 rankLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2292
2293 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2294 BOOST_CHECK(deserializedNetwork);
2295
2296 RankLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
2297 deserializedNetwork->Accept(verifier);
2298}
2299
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002300BOOST_AUTO_TEST_CASE(SerializeReshape)
2301{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002302 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Reshape)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002303
2304 const std::string layerName("reshape");
2305 const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2306 const armnn::TensorInfo outputInfo({3, 3}, armnn::DataType::Float32);
2307
2308 armnn::ReshapeDescriptor descriptor({3, 3});
2309
2310 armnn::INetworkPtr network = armnn::INetwork::Create();
2311 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2312 armnn::IConnectableLayer* const reshapeLayer = network->AddReshapeLayer(descriptor, layerName.c_str());
2313 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2314
2315 inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0));
2316 reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2317
2318 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2319 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2320
2321 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2322 BOOST_CHECK(deserializedNetwork);
2323
2324 ReshapeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2325 deserializedNetwork->Accept(verifier);
2326}
2327
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002328BOOST_AUTO_TEST_CASE(SerializeResize)
2329{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002330 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Resize)
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002331
2332 const std::string layerName("resize");
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002333 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002334 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2335
2336 armnn::ResizeDescriptor desc;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002337 desc.m_TargetWidth = 4;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002338 desc.m_TargetHeight = 2;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002339 desc.m_Method = armnn::ResizeMethod::NearestNeighbor;
David Monahan4a0c9b92020-05-30 09:48:39 +01002340 desc.m_AlignCorners = true;
2341 desc.m_HalfPixelCenters = true;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002342
2343 armnn::INetworkPtr network = armnn::INetwork::Create();
2344 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2345 armnn::IConnectableLayer* const resizeLayer = network->AddResizeLayer(desc, layerName.c_str());
2346 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2347
2348 inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2349 resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2350
2351 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2352 resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2353
2354 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2355 BOOST_CHECK(deserializedNetwork);
2356
2357 ResizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2358 deserializedNetwork->Accept(verifier);
2359}
2360
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002361class ResizeBilinearLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>
2362{
2363public:
2364 ResizeBilinearLayerVerifier(const std::string& layerName,
2365 const std::vector<armnn::TensorInfo>& inputInfos,
2366 const std::vector<armnn::TensorInfo>& outputInfos,
2367 const armnn::ResizeBilinearDescriptor& descriptor)
2368 : LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>(
2369 layerName, inputInfos, outputInfos, descriptor) {}
2370
2371 void VisitResizeLayer(const armnn::IConnectableLayer* layer,
2372 const armnn::ResizeDescriptor& descriptor,
2373 const char* name) override
2374 {
2375 VerifyNameAndConnections(layer, name);
2376
David Monahan4a0c9b92020-05-30 09:48:39 +01002377 BOOST_CHECK(descriptor.m_Method == armnn::ResizeMethod::Bilinear);
2378 BOOST_CHECK(descriptor.m_TargetWidth == m_Descriptor.m_TargetWidth);
2379 BOOST_CHECK(descriptor.m_TargetHeight == m_Descriptor.m_TargetHeight);
2380 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
2381 BOOST_CHECK(descriptor.m_AlignCorners == m_Descriptor.m_AlignCorners);
2382 BOOST_CHECK(descriptor.m_HalfPixelCenters == m_Descriptor.m_HalfPixelCenters);
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002383 }
2384
2385 void VisitResizeBilinearLayer(const armnn::IConnectableLayer*,
2386 const armnn::ResizeBilinearDescriptor&,
2387 const char*) override
2388 {
2389 throw armnn::Exception("ResizeBilinearLayer should have translated to ResizeLayer");
2390 }
2391};
2392
2393// NOTE: Until the deprecated AddResizeBilinearLayer disappears this test checks that
2394// calling AddResizeBilinearLayer places a ResizeLayer into the serialized format
2395// and that when this deserialises we have a ResizeLayer
2396BOOST_AUTO_TEST_CASE(SerializeResizeBilinear)
2397{
2398 const std::string layerName("resizeBilinear");
2399 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2400 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2401
2402 armnn::ResizeBilinearDescriptor desc;
2403 desc.m_TargetWidth = 4u;
2404 desc.m_TargetHeight = 2u;
David Monahan4a0c9b92020-05-30 09:48:39 +01002405 desc.m_AlignCorners = true;
2406 desc.m_HalfPixelCenters = true;
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002407
2408 armnn::INetworkPtr network = armnn::INetwork::Create();
2409 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2410 ARMNN_NO_DEPRECATE_WARN_BEGIN
2411 armnn::IConnectableLayer* const resizeLayer = network->AddResizeBilinearLayer(desc, layerName.c_str());
2412 ARMNN_NO_DEPRECATE_WARN_END
2413 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2414
2415 inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2416 resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2417
2418 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2419 resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2420
2421 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2422 BOOST_CHECK(deserializedNetwork);
2423
2424 ResizeBilinearLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2425 deserializedNetwork->Accept(verifier);
2426}
2427
2428BOOST_AUTO_TEST_CASE(EnsureResizeBilinearBackwardCompatibility)
2429{
2430 // The hex data below is a flat buffer containing a simple network with an input,
2431 // a ResizeBilinearLayer (now deprecated) and an output
2432 //
2433 // This test verifies that we can still deserialize this old-style model by replacing
2434 // the ResizeBilinearLayer with an equivalent ResizeLayer
2435 const std::vector<uint8_t> resizeBilinearModel =
2436 {
2437 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2438 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2439 0x50, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2440 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD4, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2441 0x04, 0x00, 0x00, 0x00, 0xC2, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
2442 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8A, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
2443 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2444 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2445 0x38, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
2446 0x00, 0x1A, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
2447 0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x08, 0x00, 0x0C, 0x00,
2448 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
2449 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00,
2450 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
2451 0x20, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x42, 0x69, 0x6C, 0x69,
2452 0x6E, 0x65, 0x61, 0x72, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2453 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
2454 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2455 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
2456 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2457 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
2458 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
2459 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00,
2460 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
2461 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00,
2463 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00,
2464 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2465 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2466 0x00, 0x00, 0x05, 0x00, 0x00, 0x00
2467 };
2468
2469 armnn::INetworkPtr deserializedNetwork =
2470 DeserializeNetwork(std::string(resizeBilinearModel.begin(), resizeBilinearModel.end()));
2471 BOOST_CHECK(deserializedNetwork);
2472
2473 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2474 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2475
2476 armnn::ResizeBilinearDescriptor descriptor;
2477 descriptor.m_TargetWidth = 4u;
2478 descriptor.m_TargetHeight = 2u;
2479
2480 ResizeBilinearLayerVerifier verifier("resizeBilinear", { inputInfo }, { outputInfo }, descriptor);
2481 deserializedNetwork->Accept(verifier);
2482}
2483
Aron Virginas-Tar2fda80b2019-09-18 13:36:52 +01002484BOOST_AUTO_TEST_CASE(SerializeSlice)
2485{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002486 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Slice)
Aron Virginas-Tar2fda80b2019-09-18 13:36:52 +01002487
2488 const std::string layerName{"slice"};
2489
2490 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2491 const armnn::TensorInfo outputInfo = armnn::TensorInfo({2, 2, 2, 1}, armnn::DataType::Float32);
2492
2493 armnn::SliceDescriptor descriptor({ 0, 0, 1, 0}, {2, 2, 2, 1});
2494
2495 armnn::INetworkPtr network = armnn::INetwork::Create();
2496
2497 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2498 armnn::IConnectableLayer* const sliceLayer = network->AddSliceLayer(descriptor, layerName.c_str());
2499 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2500
2501 inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
2502 sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2503
2504 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2505 sliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2506
2507 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2508 BOOST_CHECK(deserializedNetwork);
2509
2510 SliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2511 deserializedNetwork->Accept(verifier);
2512}
2513
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002514BOOST_AUTO_TEST_CASE(SerializeSoftmax)
2515{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002516 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Softmax)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002517
2518 const std::string layerName("softmax");
2519 const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
2520
2521 armnn::SoftmaxDescriptor descriptor;
2522 descriptor.m_Beta = 1.0f;
2523
2524 armnn::INetworkPtr network = armnn::INetwork::Create();
2525 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2526 armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, layerName.c_str());
2527 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2528
2529 inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
2530 softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2531
2532 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2533 softmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
2534
2535 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2536 BOOST_CHECK(deserializedNetwork);
2537
2538 SoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
2539 deserializedNetwork->Accept(verifier);
2540}
2541
2542BOOST_AUTO_TEST_CASE(SerializeSpaceToBatchNd)
2543{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002544 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToBatchNd)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002545
2546 const std::string layerName("spaceToBatchNd");
2547 const armnn::TensorInfo inputInfo({2, 1, 2, 4}, armnn::DataType::Float32);
2548 const armnn::TensorInfo outputInfo({8, 1, 1, 3}, armnn::DataType::Float32);
2549
2550 armnn::SpaceToBatchNdDescriptor desc;
2551 desc.m_DataLayout = armnn::DataLayout::NCHW;
2552 desc.m_BlockShape = {2, 2};
2553 desc.m_PadList = {{0, 0}, {2, 0}};
2554
2555 armnn::INetworkPtr network = armnn::INetwork::Create();
2556 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2557 armnn::IConnectableLayer* const spaceToBatchNdLayer = network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2558 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2559
2560 inputLayer->GetOutputSlot(0).Connect(spaceToBatchNdLayer->GetInputSlot(0));
2561 spaceToBatchNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2562
2563 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2564 spaceToBatchNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2565
2566 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2567 BOOST_CHECK(deserializedNetwork);
2568
2569 SpaceToBatchNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2570 deserializedNetwork->Accept(verifier);
2571}
2572
Aron Virginas-Taraa067142019-06-11 16:01:44 +01002573BOOST_AUTO_TEST_CASE(SerializeSpaceToDepth)
2574{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002575 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToDepth)
Aron Virginas-Taraa067142019-06-11 16:01:44 +01002576
2577 const std::string layerName("spaceToDepth");
2578
2579 const armnn::TensorInfo inputInfo ({ 1, 16, 8, 3 }, armnn::DataType::Float32);
2580 const armnn::TensorInfo outputInfo({ 1, 8, 4, 12 }, armnn::DataType::Float32);
2581
2582 armnn::SpaceToDepthDescriptor desc;
2583 desc.m_BlockSize = 2;
2584 desc.m_DataLayout = armnn::DataLayout::NHWC;
2585
2586 armnn::INetworkPtr network = armnn::INetwork::Create();
2587 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2588 armnn::IConnectableLayer* const spaceToDepthLayer = network->AddSpaceToDepthLayer(desc, layerName.c_str());
2589 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2590
2591 inputLayer->GetOutputSlot(0).Connect(spaceToDepthLayer->GetInputSlot(0));
2592 spaceToDepthLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2593
2594 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2595 spaceToDepthLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2596
2597 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2598 BOOST_CHECK(deserializedNetwork);
2599
2600 SpaceToDepthLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2601 deserializedNetwork->Accept(verifier);
2602}
2603
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002604BOOST_AUTO_TEST_CASE(SerializeSplitter)
2605{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002606 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Splitter)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002607
2608 const unsigned int numViews = 3;
2609 const unsigned int numDimensions = 4;
2610 const unsigned int inputShape[] = {1, 18, 4, 4};
2611 const unsigned int outputShape[] = {1, 6, 4, 4};
2612
2613 // This is modelled on how the caffe parser sets up a splitter layer to partition an input along dimension one.
2614 unsigned int splitterDimSizes[4] = {static_cast<unsigned int>(inputShape[0]),
2615 static_cast<unsigned int>(inputShape[1]),
2616 static_cast<unsigned int>(inputShape[2]),
2617 static_cast<unsigned int>(inputShape[3])};
2618 splitterDimSizes[1] /= numViews;
2619 armnn::ViewsDescriptor desc(numViews, numDimensions);
2620
2621 for (unsigned int g = 0; g < numViews; ++g)
2622 {
2623 desc.SetViewOriginCoord(g, 1, splitterDimSizes[1] * g);
2624
2625 for (unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
2626 {
2627 desc.SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
2628 }
2629 }
2630
2631 const std::string layerName("splitter");
2632 const armnn::TensorInfo inputInfo(numDimensions, inputShape, armnn::DataType::Float32);
2633 const armnn::TensorInfo outputInfo(numDimensions, outputShape, armnn::DataType::Float32);
2634
2635 armnn::INetworkPtr network = armnn::INetwork::Create();
2636 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2637 armnn::IConnectableLayer* const splitterLayer = network->AddSplitterLayer(desc, layerName.c_str());
2638 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2639 armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2640 armnn::IConnectableLayer* const outputLayer2 = network->AddOutputLayer(2);
2641
2642 inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
2643 splitterLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2644 splitterLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2645 splitterLayer->GetOutputSlot(2).Connect(outputLayer2->GetInputSlot(0));
2646
2647 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2648 splitterLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2649 splitterLayer->GetOutputSlot(1).SetTensorInfo(outputInfo);
2650 splitterLayer->GetOutputSlot(2).SetTensorInfo(outputInfo);
2651
2652 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2653 BOOST_CHECK(deserializedNetwork);
2654
2655 SplitterLayerVerifier verifier(layerName, {inputInfo}, {outputInfo, outputInfo, outputInfo}, desc);
2656 deserializedNetwork->Accept(verifier);
2657}
2658
Matthew Jacksonb5433ee2019-07-11 15:54:20 +01002659BOOST_AUTO_TEST_CASE(SerializeStack)
2660{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002661 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Stack)
Matthew Jacksonb5433ee2019-07-11 15:54:20 +01002662
2663 const std::string layerName("stack");
2664
2665 armnn::TensorInfo inputTensorInfo ({4, 3, 5}, armnn::DataType::Float32);
2666 armnn::TensorInfo outputTensorInfo({4, 3, 2, 5}, armnn::DataType::Float32);
2667
2668 armnn::StackDescriptor descriptor(2, 2, {4, 3, 5});
2669
2670 armnn::INetworkPtr network = armnn::INetwork::Create();
2671 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
2672 armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
2673 armnn::IConnectableLayer* const stackLayer = network->AddStackLayer(descriptor, layerName.c_str());
2674 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2675
2676 inputLayer1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
2677 inputLayer2->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
2678 stackLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2679
2680 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2681 inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2682 stackLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2683
2684 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2685 BOOST_CHECK(deserializedNetwork);
2686
2687 StackLayerVerifier verifier(layerName, {inputTensorInfo, inputTensorInfo}, {outputTensorInfo}, descriptor);
2688 deserializedNetwork->Accept(verifier);
2689}
2690
Aron Virginas-Tar85121a22019-10-23 10:41:35 +01002691BOOST_AUTO_TEST_CASE(SerializeStandIn)
2692{
2693 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StandIn)
2694
2695 const std::string layerName("standIn");
2696
2697 armnn::TensorInfo tensorInfo({ 1u }, armnn::DataType::Float32);
2698 armnn::StandInDescriptor descriptor(2u, 2u);
2699
2700 armnn::INetworkPtr network = armnn::INetwork::Create();
2701 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2702 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2703 armnn::IConnectableLayer* const standInLayer = network->AddStandInLayer(descriptor, layerName.c_str());
2704 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2705 armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2706
2707 inputLayer0->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(0));
2708 inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2709
2710 inputLayer1->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(1));
2711 inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2712
2713 standInLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2714 standInLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2715
2716 standInLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2717 standInLayer->GetOutputSlot(1).SetTensorInfo(tensorInfo);
2718
2719 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2720 BOOST_CHECK(deserializedNetwork);
2721
2722 StandInLayerVerifier verifier(layerName, { tensorInfo, tensorInfo }, { tensorInfo, tensorInfo }, descriptor);
2723 deserializedNetwork->Accept(verifier);
2724}
2725
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002726BOOST_AUTO_TEST_CASE(SerializeStridedSlice)
2727{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002728 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StridedSlice)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002729
2730 const std::string layerName("stridedSlice");
2731 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2732 const armnn::TensorInfo outputInfo = armnn::TensorInfo({3, 1}, armnn::DataType::Float32);
2733
2734 armnn::StridedSliceDescriptor desc({0, 0, 1, 0}, {1, 1, 1, 1}, {1, 1, 1, 1});
2735 desc.m_EndMask = (1 << 4) - 1;
2736 desc.m_ShrinkAxisMask = (1 << 1) | (1 << 2);
2737 desc.m_DataLayout = armnn::DataLayout::NCHW;
2738
2739 armnn::INetworkPtr network = armnn::INetwork::Create();
2740 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2741 armnn::IConnectableLayer* const stridedSliceLayer = network->AddStridedSliceLayer(desc, layerName.c_str());
2742 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2743
2744 inputLayer->GetOutputSlot(0).Connect(stridedSliceLayer->GetInputSlot(0));
2745 stridedSliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2746
2747 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2748 stridedSliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2749
2750 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2751 BOOST_CHECK(deserializedNetwork);
2752
2753 StridedSliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2754 deserializedNetwork->Accept(verifier);
2755}
2756
2757BOOST_AUTO_TEST_CASE(SerializeSubtraction)
2758{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002759 DECLARE_LAYER_VERIFIER_CLASS(Subtraction)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002760
2761 const std::string layerName("subtraction");
2762 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2763
2764 armnn::INetworkPtr network = armnn::INetwork::Create();
2765 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2766 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2767 armnn::IConnectableLayer* const subtractionLayer = network->AddSubtractionLayer(layerName.c_str());
2768 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2769
2770 inputLayer0->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(0));
2771 inputLayer1->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(1));
2772 subtractionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2773
2774 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2775 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2776 subtractionLayer->GetOutputSlot(0).SetTensorInfo(info);
2777
2778 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2779 BOOST_CHECK(deserializedNetwork);
2780
2781 SubtractionLayerVerifier verifier(layerName, {info, info}, {info});
2782 deserializedNetwork->Accept(verifier);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00002783}
2784
Sadik Armaganeff363d2019-04-05 15:25:46 +01002785BOOST_AUTO_TEST_CASE(SerializeSwitch)
2786{
2787 class SwitchLayerVerifier : public LayerVerifierBase
2788 {
2789 public:
2790 SwitchLayerVerifier(const std::string& layerName,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002791 const std::vector<armnn::TensorInfo>& inputInfos,
2792 const std::vector<armnn::TensorInfo>& outputInfos)
Sadik Armaganeff363d2019-04-05 15:25:46 +01002793 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2794
2795 void VisitSwitchLayer(const armnn::IConnectableLayer* layer, const char* name) override
2796 {
2797 VerifyNameAndConnections(layer, name);
2798 }
2799
Derek Lamberti859f9ce2019-12-10 22:05:21 +00002800 void VisitConstantLayer(const armnn::IConnectableLayer*,
2801 const armnn::ConstTensor&,
2802 const char*) override {}
Sadik Armaganeff363d2019-04-05 15:25:46 +01002803 };
2804
2805 const std::string layerName("switch");
2806 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2807
2808 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2809 armnn::ConstTensor constTensor(info, constantData);
2810
2811 armnn::INetworkPtr network = armnn::INetwork::Create();
2812 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2813 armnn::IConnectableLayer* const constantLayer = network->AddConstantLayer(constTensor, "constant");
2814 armnn::IConnectableLayer* const switchLayer = network->AddSwitchLayer(layerName.c_str());
2815 armnn::IConnectableLayer* const trueOutputLayer = network->AddOutputLayer(0);
2816 armnn::IConnectableLayer* const falseOutputLayer = network->AddOutputLayer(1);
2817
2818 inputLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(0));
2819 constantLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(1));
2820 switchLayer->GetOutputSlot(0).Connect(trueOutputLayer->GetInputSlot(0));
2821 switchLayer->GetOutputSlot(1).Connect(falseOutputLayer->GetInputSlot(0));
2822
2823 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2824 constantLayer->GetOutputSlot(0).SetTensorInfo(info);
2825 switchLayer->GetOutputSlot(0).SetTensorInfo(info);
2826 switchLayer->GetOutputSlot(1).SetTensorInfo(info);
2827
2828 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2829 BOOST_CHECK(deserializedNetwork);
2830
2831 SwitchLayerVerifier verifier(layerName, {info, info}, {info, info});
2832 deserializedNetwork->Accept(verifier);
2833}
2834
Mike Kellyc9ea45a2020-02-28 18:11:58 +00002835BOOST_AUTO_TEST_CASE(SerializeTranspose)
2836{
2837 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Transpose)
2838
2839 const std::string layerName("transpose");
2840 const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2841 const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2842
2843 armnn::TransposeDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2844
2845 armnn::INetworkPtr network = armnn::INetwork::Create();
2846 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2847 armnn::IConnectableLayer* const transposeLayer = network->AddTransposeLayer(descriptor, layerName.c_str());
2848 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2849
2850 inputLayer->GetOutputSlot(0).Connect(transposeLayer->GetInputSlot(0));
2851 transposeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2852
2853 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2854 transposeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2855
2856 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2857 BOOST_CHECK(deserializedNetwork);
2858
2859 TransposeLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2860 deserializedNetwork->Accept(verifier);
2861}
2862
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002863BOOST_AUTO_TEST_CASE(SerializeTransposeConvolution2d)
2864{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002865 using Descriptor = armnn::TransposeConvolution2dDescriptor;
2866 class TransposeConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002867 {
2868 public:
2869 TransposeConvolution2dLayerVerifier(const std::string& layerName,
2870 const std::vector<armnn::TensorInfo>& inputInfos,
2871 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002872 const Descriptor& descriptor,
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002873 const armnn::ConstTensor& weights,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002874 const armnn::Optional<armnn::ConstTensor>& biases)
2875 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
2876 , m_Weights(weights)
2877 , m_Biases(biases)
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002878 {}
2879
2880 void VisitTransposeConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002881 const Descriptor& descriptor,
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002882 const armnn::ConstTensor& weights,
2883 const armnn::Optional<armnn::ConstTensor>& biases,
2884 const char* name) override
2885 {
2886 VerifyNameAndConnections(layer, name);
2887 VerifyDescriptor(descriptor);
2888
2889 // check weights
2890 CompareConstTensor(weights, m_Weights);
2891
2892 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002893 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002894 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
2895
2896 if (biases.has_value() && m_Biases.has_value())
2897 {
2898 CompareConstTensor(biases.value(), m_Biases.value());
2899 }
2900 }
2901
2902 private:
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002903 armnn::ConstTensor m_Weights;
2904 armnn::Optional<armnn::ConstTensor> m_Biases;
2905 };
2906
2907 const std::string layerName("transposeConvolution2d");
2908 const armnn::TensorInfo inputInfo ({ 1, 7, 7, 1 }, armnn::DataType::Float32);
2909 const armnn::TensorInfo outputInfo({ 1, 9, 9, 1 }, armnn::DataType::Float32);
2910
2911 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
2912 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
2913
2914 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
2915 armnn::ConstTensor weights(weightsInfo, weightsData);
2916
2917 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
2918 armnn::ConstTensor biases(biasesInfo, biasesData);
2919
2920 armnn::TransposeConvolution2dDescriptor descriptor;
2921 descriptor.m_PadLeft = 1;
2922 descriptor.m_PadRight = 1;
2923 descriptor.m_PadTop = 1;
2924 descriptor.m_PadBottom = 1;
2925 descriptor.m_StrideX = 1;
2926 descriptor.m_StrideY = 1;
2927 descriptor.m_BiasEnabled = true;
2928 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
2929
2930 armnn::INetworkPtr network = armnn::INetwork::Create();
2931 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2932 armnn::IConnectableLayer* const convLayer =
2933 network->AddTransposeConvolution2dLayer(descriptor,
2934 weights,
2935 armnn::Optional<armnn::ConstTensor>(biases),
2936 layerName.c_str());
2937 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2938
2939 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
2940 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2941
2942 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2943 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2944
2945 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2946 BOOST_CHECK(deserializedNetwork);
2947
2948 TransposeConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
2949 deserializedNetwork->Accept(verifier);
2950}
2951
Sadik Armagandb059fd2019-03-20 12:28:32 +00002952BOOST_AUTO_TEST_CASE(SerializeDeserializeNonLinearNetwork)
2953{
2954 class ConstantLayerVerifier : public LayerVerifierBase
2955 {
2956 public:
2957 ConstantLayerVerifier(const std::string& layerName,
2958 const std::vector<armnn::TensorInfo>& inputInfos,
2959 const std::vector<armnn::TensorInfo>& outputInfos,
2960 const armnn::ConstTensor& layerInput)
2961 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2962 , m_LayerInput(layerInput) {}
2963
2964 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
2965 const armnn::ConstTensor& input,
2966 const char* name) override
2967 {
2968 VerifyNameAndConnections(layer, name);
Sadik Armagandb059fd2019-03-20 12:28:32 +00002969 CompareConstTensor(input, m_LayerInput);
2970 }
2971
Derek Lamberti859f9ce2019-12-10 22:05:21 +00002972 void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
Sadik Armagandb059fd2019-03-20 12:28:32 +00002973
2974 private:
2975 armnn::ConstTensor m_LayerInput;
2976 };
2977
2978 const std::string layerName("constant");
2979 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
2980
2981 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2982 armnn::ConstTensor constTensor(info, constantData);
2983
2984 armnn::INetworkPtr network(armnn::INetwork::Create());
2985 armnn::IConnectableLayer* input = network->AddInputLayer(0);
2986 armnn::IConnectableLayer* add = network->AddAdditionLayer();
2987 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
2988 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
2989
2990 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
2991 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
2992 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2993
2994 input->GetOutputSlot(0).SetTensorInfo(info);
2995 constant->GetOutputSlot(0).SetTensorInfo(info);
2996 add->GetOutputSlot(0).SetTensorInfo(info);
2997
2998 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2999 BOOST_CHECK(deserializedNetwork);
3000
3001 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
3002 deserializedNetwork->Accept(verifier);
3003}
3004
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003005class VerifyLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>
Jim Flynn11af3752019-03-19 17:22:29 +00003006{
3007public:
3008 VerifyLstmLayer(const std::string& layerName,
3009 const std::vector<armnn::TensorInfo>& inputInfos,
3010 const std::vector<armnn::TensorInfo>& outputInfos,
3011 const armnn::LstmDescriptor& descriptor,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003012 const armnn::LstmInputParams& inputParams)
3013 : LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
3014 , m_InputParams(inputParams) {}
3015
Jim Flynn11af3752019-03-19 17:22:29 +00003016 void VisitLstmLayer(const armnn::IConnectableLayer* layer,
3017 const armnn::LstmDescriptor& descriptor,
3018 const armnn::LstmInputParams& params,
3019 const char* name)
3020 {
3021 VerifyNameAndConnections(layer, name);
3022 VerifyDescriptor(descriptor);
3023 VerifyInputParameters(params);
3024 }
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003025
Jim Flynn11af3752019-03-19 17:22:29 +00003026protected:
Jim Flynn11af3752019-03-19 17:22:29 +00003027 void VerifyInputParameters(const armnn::LstmInputParams& params)
3028 {
3029 VerifyConstTensors(
3030 "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
3031 VerifyConstTensors(
3032 "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
3033 VerifyConstTensors(
3034 "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
3035 VerifyConstTensors(
3036 "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
3037 VerifyConstTensors(
3038 "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
3039 VerifyConstTensors(
3040 "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
3041 VerifyConstTensors(
3042 "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
3043 VerifyConstTensors(
3044 "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
3045 VerifyConstTensors(
3046 "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
3047 VerifyConstTensors(
3048 "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
3049 VerifyConstTensors(
3050 "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
3051 VerifyConstTensors(
3052 "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
3053 VerifyConstTensors(
3054 "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
3055 VerifyConstTensors(
3056 "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
3057 VerifyConstTensors(
3058 "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
3059 VerifyConstTensors(
3060 "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
3061 VerifyConstTensors(
3062 "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
Jan Eilersf8c62972019-07-17 11:07:49 +01003063 VerifyConstTensors(
3064 "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
3065 VerifyConstTensors(
3066 "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
3067 VerifyConstTensors(
3068 "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
3069 VerifyConstTensors(
3070 "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
Jim Flynn11af3752019-03-19 17:22:29 +00003071 }
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01003072
Jim Flynn11af3752019-03-19 17:22:29 +00003073private:
Jim Flynn11af3752019-03-19 17:22:29 +00003074 armnn::LstmInputParams m_InputParams;
3075};
3076
3077BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmCifgPeepholeNoProjection)
3078{
3079 armnn::LstmDescriptor descriptor;
3080 descriptor.m_ActivationFunc = 4;
3081 descriptor.m_ClippingThresProj = 0.0f;
3082 descriptor.m_ClippingThresCell = 0.0f;
3083 descriptor.m_CifgEnabled = true; // if this is true then we DON'T need to set the OptCifgParams
3084 descriptor.m_ProjectionEnabled = false;
3085 descriptor.m_PeepholeEnabled = true;
3086
3087 const uint32_t batchSize = 1;
3088 const uint32_t inputSize = 2;
3089 const uint32_t numUnits = 4;
3090 const uint32_t outputSize = numUnits;
3091
3092 armnn::TensorInfo inputWeightsInfo1({numUnits, inputSize}, armnn::DataType::Float32);
3093 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3094 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo1, inputToForgetWeightsData);
3095
3096 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3097 armnn::ConstTensor inputToCellWeights(inputWeightsInfo1, inputToCellWeightsData);
3098
3099 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3100 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo1, inputToOutputWeightsData);
3101
3102 armnn::TensorInfo inputWeightsInfo2({numUnits, outputSize}, armnn::DataType::Float32);
3103 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3104 armnn::ConstTensor recurrentToForgetWeights(inputWeightsInfo2, recurrentToForgetWeightsData);
3105
3106 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3107 armnn::ConstTensor recurrentToCellWeights(inputWeightsInfo2, recurrentToCellWeightsData);
3108
3109 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3110 armnn::ConstTensor recurrentToOutputWeights(inputWeightsInfo2, recurrentToOutputWeightsData);
3111
3112 armnn::TensorInfo inputWeightsInfo3({numUnits}, armnn::DataType::Float32);
3113 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3114 armnn::ConstTensor cellToForgetWeights(inputWeightsInfo3, cellToForgetWeightsData);
3115
3116 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3117 armnn::ConstTensor cellToOutputWeights(inputWeightsInfo3, cellToOutputWeightsData);
3118
3119 std::vector<float> forgetGateBiasData(numUnits, 1.0f);
3120 armnn::ConstTensor forgetGateBias(inputWeightsInfo3, forgetGateBiasData);
3121
3122 std::vector<float> cellBiasData(numUnits, 0.0f);
3123 armnn::ConstTensor cellBias(inputWeightsInfo3, cellBiasData);
3124
3125 std::vector<float> outputGateBiasData(numUnits, 0.0f);
3126 armnn::ConstTensor outputGateBias(inputWeightsInfo3, outputGateBiasData);
3127
3128 armnn::LstmInputParams params;
3129 params.m_InputToForgetWeights = &inputToForgetWeights;
3130 params.m_InputToCellWeights = &inputToCellWeights;
3131 params.m_InputToOutputWeights = &inputToOutputWeights;
3132 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3133 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3134 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3135 params.m_ForgetGateBias = &forgetGateBias;
3136 params.m_CellBias = &cellBias;
3137 params.m_OutputGateBias = &outputGateBias;
3138 params.m_CellToForgetWeights = &cellToForgetWeights;
3139 params.m_CellToOutputWeights = &cellToOutputWeights;
3140
3141 armnn::INetworkPtr network = armnn::INetwork::Create();
3142 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3143 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3144 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3145 const std::string layerName("lstm");
3146 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3147 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3148 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3149 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3150 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3151
3152 // connect up
3153 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3154 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3155 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3156 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 3 }, armnn::DataType::Float32);
3157
3158 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3159 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3160
3161 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3162 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3163
3164 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3165 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3166
3167 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3168 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3169
3170 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3171 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3172
3173 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3174 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3175
3176 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3177 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3178
3179 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3180 BOOST_CHECK(deserializedNetwork);
3181
3182 VerifyLstmLayer checker(
3183 layerName,
3184 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3185 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3186 descriptor,
3187 params);
3188 deserializedNetwork->Accept(checker);
3189}
3190
3191BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeAndProjection)
3192{
3193 armnn::LstmDescriptor descriptor;
3194 descriptor.m_ActivationFunc = 4;
3195 descriptor.m_ClippingThresProj = 0.0f;
3196 descriptor.m_ClippingThresCell = 0.0f;
3197 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3198 descriptor.m_ProjectionEnabled = true;
3199 descriptor.m_PeepholeEnabled = true;
3200
3201 const uint32_t batchSize = 2;
3202 const uint32_t inputSize = 5;
3203 const uint32_t numUnits = 20;
3204 const uint32_t outputSize = 16;
3205
3206 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3207 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3208 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3209
3210 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3211 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3212
3213 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3214 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3215
3216 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3217 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3218
3219 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3220 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3221 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3222
3223 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3224 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3225
3226 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3227 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3228
3229 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3230 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3231
3232 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3233 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3234 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3235
3236 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3237 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3238
3239 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3240 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3241
3242 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3243 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3244
3245 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3246 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3247
3248 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3249 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3250
3251 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3252 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3253
3254 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3255 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3256 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3257
3258 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3259 std::vector<float> projectionBiasData(outputSize, 0.f);
3260 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3261
3262 armnn::LstmInputParams params;
3263 params.m_InputToForgetWeights = &inputToForgetWeights;
3264 params.m_InputToCellWeights = &inputToCellWeights;
3265 params.m_InputToOutputWeights = &inputToOutputWeights;
3266 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3267 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3268 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3269 params.m_ForgetGateBias = &forgetGateBias;
3270 params.m_CellBias = &cellBias;
3271 params.m_OutputGateBias = &outputGateBias;
3272
3273 // additional params because: descriptor.m_CifgEnabled = false
3274 params.m_InputToInputWeights = &inputToInputWeights;
3275 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3276 params.m_CellToInputWeights = &cellToInputWeights;
3277 params.m_InputGateBias = &inputGateBias;
3278
3279 // additional params because: descriptor.m_ProjectionEnabled = true
3280 params.m_ProjectionWeights = &projectionWeights;
3281 params.m_ProjectionBias = &projectionBias;
3282
3283 // additional params because: descriptor.m_PeepholeEnabled = true
3284 params.m_CellToForgetWeights = &cellToForgetWeights;
3285 params.m_CellToOutputWeights = &cellToOutputWeights;
3286
3287 armnn::INetworkPtr network = armnn::INetwork::Create();
3288 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3289 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3290 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3291 const std::string layerName("lstm");
3292 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3293 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3294 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3295 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3296 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3297
3298 // connect up
3299 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3300 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3301 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3302 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3303
3304 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3305 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3306
3307 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3308 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3309
3310 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3311 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3312
3313 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3314 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3315
3316 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3317 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3318
3319 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3320 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3321
3322 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3323 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3324
3325 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3326 BOOST_CHECK(deserializedNetwork);
3327
3328 VerifyLstmLayer checker(
3329 layerName,
3330 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3331 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3332 descriptor,
3333 params);
3334 deserializedNetwork->Accept(checker);
3335}
3336
Jan Eilersf8c62972019-07-17 11:07:49 +01003337BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeWithProjectionWithLayerNorm)
3338{
3339 armnn::LstmDescriptor descriptor;
3340 descriptor.m_ActivationFunc = 4;
3341 descriptor.m_ClippingThresProj = 0.0f;
3342 descriptor.m_ClippingThresCell = 0.0f;
3343 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3344 descriptor.m_ProjectionEnabled = true;
3345 descriptor.m_PeepholeEnabled = true;
3346 descriptor.m_LayerNormEnabled = true;
3347
3348 const uint32_t batchSize = 2;
3349 const uint32_t inputSize = 5;
3350 const uint32_t numUnits = 20;
3351 const uint32_t outputSize = 16;
3352
3353 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3354 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3355 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3356
3357 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3358 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3359
3360 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3361 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3362
3363 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3364 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3365
3366 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3367 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3368 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3369
3370 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3371 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3372
3373 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3374 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3375
3376 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3377 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3378
3379 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3380 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3381 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3382
3383 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3384 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3385
3386 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3387 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3388
3389 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3390 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3391
3392 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3393 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3394
3395 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3396 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3397
3398 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3399 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3400
3401 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3402 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3403 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3404
3405 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3406 std::vector<float> projectionBiasData(outputSize, 0.f);
3407 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3408
3409 std::vector<float> inputLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3410 armnn::ConstTensor inputLayerNormWeights(tensorInfo20, forgetGateBiasData);
3411
3412 std::vector<float> forgetLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3413 armnn::ConstTensor forgetLayerNormWeights(tensorInfo20, forgetGateBiasData);
3414
3415 std::vector<float> cellLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3416 armnn::ConstTensor cellLayerNormWeights(tensorInfo20, forgetGateBiasData);
3417
3418 std::vector<float> outLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3419 armnn::ConstTensor outLayerNormWeights(tensorInfo20, forgetGateBiasData);
3420
3421 armnn::LstmInputParams params;
3422 params.m_InputToForgetWeights = &inputToForgetWeights;
3423 params.m_InputToCellWeights = &inputToCellWeights;
3424 params.m_InputToOutputWeights = &inputToOutputWeights;
3425 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3426 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3427 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3428 params.m_ForgetGateBias = &forgetGateBias;
3429 params.m_CellBias = &cellBias;
3430 params.m_OutputGateBias = &outputGateBias;
3431
3432 // additional params because: descriptor.m_CifgEnabled = false
3433 params.m_InputToInputWeights = &inputToInputWeights;
3434 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3435 params.m_CellToInputWeights = &cellToInputWeights;
3436 params.m_InputGateBias = &inputGateBias;
3437
3438 // additional params because: descriptor.m_ProjectionEnabled = true
3439 params.m_ProjectionWeights = &projectionWeights;
3440 params.m_ProjectionBias = &projectionBias;
3441
3442 // additional params because: descriptor.m_PeepholeEnabled = true
3443 params.m_CellToForgetWeights = &cellToForgetWeights;
3444 params.m_CellToOutputWeights = &cellToOutputWeights;
3445
3446 // additional params because: despriptor.m_LayerNormEnabled = true
3447 params.m_InputLayerNormWeights = &inputLayerNormWeights;
3448 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3449 params.m_CellLayerNormWeights = &cellLayerNormWeights;
3450 params.m_OutputLayerNormWeights = &outLayerNormWeights;
3451
3452 armnn::INetworkPtr network = armnn::INetwork::Create();
3453 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3454 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3455 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3456 const std::string layerName("lstm");
3457 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3458 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3459 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3460 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3461 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3462
3463 // connect up
3464 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3465 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3466 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3467 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3468
3469 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3470 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3471
3472 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3473 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3474
3475 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3476 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3477
3478 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3479 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3480
3481 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3482 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3483
3484 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3485 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3486
3487 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3488 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3489
3490 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3491 BOOST_CHECK(deserializedNetwork);
3492
3493 VerifyLstmLayer checker(
3494 layerName,
3495 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3496 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3497 descriptor,
3498 params);
3499 deserializedNetwork->Accept(checker);
3500}
3501
3502BOOST_AUTO_TEST_CASE(EnsureLstmLayersBackwardCompatibility)
3503{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003504 // The hex data below is a flat buffer containing a lstm layer with no Cifg, with peephole and projection
3505 // enabled. That data was obtained before additional layer normalization parameters where added to the
3506 // lstm serializer. That way it can be tested if a lstm model with the old parameter configuration can
3507 // still be loaded
3508 const std::vector<uint8_t> lstmNoCifgWithPeepholeAndProjectionModel =
Jan Eilersf8c62972019-07-17 11:07:49 +01003509 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003510 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
3511 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
3512 0xDC, 0x29, 0x00, 0x00, 0x38, 0x29, 0x00, 0x00, 0xB4, 0x28, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x3C, 0x01,
3513 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
3514 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
3515 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0xD6, 0xFF, 0xFF,
3516 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x06, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x88, 0xD7,
3517 0xFF, 0xFF, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF6, 0xD6, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
3518 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
3519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3520 0xE8, 0xD7, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xFF, 0xFF, 0x00, 0x00,
3521 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x5E, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xE0, 0xD7, 0xFF, 0xFF,
3522 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4E, 0xD7, 0xFF, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00,
3523 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3524 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD8,
3525 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
3526 0x04, 0x00, 0x00, 0x00, 0xB6, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x38, 0xD8, 0xFF, 0xFF, 0x08, 0x00,
3527 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA6, 0xD7, 0xFF, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3528 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3529 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xD8, 0xFF, 0xFF,
3530 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00,
3531 0x00, 0x00, 0x0E, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x16, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3532 0xFA, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00,
3533 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3534 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
3535 0x00, 0x00, 0x6C, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
3536 0x12, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE0, 0x25, 0x00, 0x00, 0xD0, 0x25,
3537 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x48, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00,
3538 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2C, 0x00, 0x30, 0x00,
3539 0x34, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x40, 0x00, 0x44, 0x00, 0x26, 0x00, 0x00, 0x00, 0xC4, 0x23, 0x00, 0x00,
3540 0xF8, 0x21, 0x00, 0x00, 0x2C, 0x20, 0x00, 0x00, 0xF0, 0x1A, 0x00, 0x00, 0xB4, 0x15, 0x00, 0x00, 0x78, 0x10,
3541 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x68, 0x0F, 0x00, 0x00, 0xE0, 0x0E, 0x00, 0x00, 0x14, 0x0D, 0x00, 0x00,
3542 0xD8, 0x07, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0xC8, 0x06, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x14, 0x01,
3543 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3544 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00,
3545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3550 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x72, 0xD8,
3551 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0xD9, 0xFF, 0xFF,
3552 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xD8,
3557 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3558 0x14, 0x00, 0x00, 0x00, 0xF6, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x54, 0x00, 0x00, 0x00, 0x04, 0x00,
3559 0x00, 0x00, 0x06, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xD9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3564 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6A, 0xD9, 0xFF, 0xFF, 0x00, 0x00,
3565 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7A, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3566 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3581 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xDE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3638 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xA2, 0xDE,
3639 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB2, 0xDF, 0xFF, 0xFF,
3640 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xDF,
3645 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3646 0x14, 0x00, 0x00, 0x00, 0x26, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00,
3647 0x00, 0x00, 0x36, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3652 0x00, 0x00, 0x00, 0x00, 0x92, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3653 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAA, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3654 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xBA, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3663 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3690 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3693 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3694 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3695 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3696 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3700 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3703 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3704 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3705 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3706 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3707 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3708 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3709 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3711 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3712 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3716 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3717 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3718 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3720 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3721 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3722 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3725 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3726 0x00, 0x00, 0x00, 0x00, 0xC6, 0xE4, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3727 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xE2, 0xE4, 0xFF, 0xFF,
3728 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xE5, 0xFF, 0xFF, 0x04, 0x00,
3729 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3730 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3732 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3733 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3734 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3735 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3736 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3737 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3738 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3739 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3740 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3741 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3746 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3752 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
3753 0x00, 0x00, 0xAA, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3754 0xBA, 0xE7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3755 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3759 0x00, 0x00, 0x16, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3760 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2E, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00,
3761 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3E, 0xE8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
3762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xB2, 0xE7, 0xFF, 0xFF,
3768 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC2, 0xE8, 0xFF, 0xFF, 0x04, 0x00,
3769 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE8, 0xFF, 0xFF,
3774 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00,
3775 0x00, 0x00, 0x36, 0xE8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3776 0x46, 0xE9, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3786 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3788 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3791 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3793 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3805 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0xFF, 0xFF,
3848 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00,
3849 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6E, 0xED, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00,
3850 0x04, 0x00, 0x00, 0x00, 0x7E, 0xEE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00,
3851 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3859 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3860 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3861 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3862 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3863 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3864 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3865 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3866 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3868 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3869 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3870 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3873 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3874 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3875 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3876 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3877 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3878 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3879 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3880 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3881 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3882 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3883 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3884 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3885 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3886 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3887 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3889 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3892 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3894 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3896 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3897 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3898 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3899 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3900 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3901 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3902 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3903 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3904 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3905 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3906 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3907 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3908 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3909 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3910 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3911 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3912 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3913 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3915 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3916 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3917 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3918 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3919 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3920 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3921 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3922 0x8A, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3923 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xA6, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3924 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB6, 0xF3, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3925 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3927 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3929 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3930 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3931 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3932 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3933 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3935 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3936 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3938 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3939 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3940 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3941 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3942 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3943 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3944 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3945 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3946 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3947 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3948 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3949 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3950 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3951 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3952 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3953 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3954 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3955 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3956 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3957 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3958 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3959 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3960 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3961 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3962 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3963 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3964 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3965 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3966 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3967 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3968 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3969 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3970 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3971 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3972 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3973 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3974 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3975 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3976 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3977 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3986 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3988 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3992 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3993 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3994 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3995 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3996 0x00, 0x00, 0x00, 0x00, 0xC2, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3997 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xDE, 0xF7, 0xFF, 0xFF,
3998 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xF8, 0xFF, 0xFF, 0x04, 0x00,
3999 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4000 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4001 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4002 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4004 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4006 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4007 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4009 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4010 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4011 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4012 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4013 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4014 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4015 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4016 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4017 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4018 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4019 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4020 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4021 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
4022 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
4023 0x00, 0x00, 0xA6, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4024 0xB6, 0xFA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4026 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4027 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4030 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4031 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4032 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4033 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4034 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4035 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4037 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4046 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xFB,
4047 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
4048 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6E, 0xFB, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01,
4049 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFC, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
4050 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4051 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4055 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4059 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4062 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4063 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4064 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4065 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4068 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4069 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4070 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4072 0x00, 0x00, 0x00, 0x00, 0x1A, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4073 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x00,
4074 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
4075 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x2E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4076 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6C, 0x73,
4077 0x74, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00,
4078 0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x30, 0x00,
4079 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4080 0xA6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
4081 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
4082 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4083 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x64, 0xFF, 0xFF, 0xFF,
4084 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4085 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4086 0xB4, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x1A, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4087 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
4088 0xF0, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
4089 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
4090 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
4091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
4092 0x7E, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00,
4093 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x76, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
4094 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
4095 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4096 0x68, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
4097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
4098 0x08, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00,
4099 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4100 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00,
4101 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00,
4102 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
4103 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4104 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4105 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6E, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
4106 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00,
4107 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
4108 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00,
4109 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4110 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
4111 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4112 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
4113 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00,
4114 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
4115 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00
4116 };
4117
4118 armnn::INetworkPtr deserializedNetwork =
4119 DeserializeNetwork(std::string(lstmNoCifgWithPeepholeAndProjectionModel.begin(),
4120 lstmNoCifgWithPeepholeAndProjectionModel.end()));
4121
Jan Eilersf8c62972019-07-17 11:07:49 +01004122 BOOST_CHECK(deserializedNetwork);
4123
4124 // generating the same model parameters which where used to serialize the model (Layer norm is not specified)
4125 armnn::LstmDescriptor descriptor;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004126 descriptor.m_ActivationFunc = 4;
Jan Eilersf8c62972019-07-17 11:07:49 +01004127 descriptor.m_ClippingThresProj = 0.0f;
4128 descriptor.m_ClippingThresCell = 0.0f;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004129 descriptor.m_CifgEnabled = false;
Jan Eilersf8c62972019-07-17 11:07:49 +01004130 descriptor.m_ProjectionEnabled = true;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004131 descriptor.m_PeepholeEnabled = true;
Jan Eilersf8c62972019-07-17 11:07:49 +01004132
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004133 const uint32_t batchSize = 2u;
4134 const uint32_t inputSize = 5u;
4135 const uint32_t numUnits = 20u;
4136 const uint32_t outputSize = 16u;
Jan Eilersf8c62972019-07-17 11:07:49 +01004137
4138 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
4139 std::vector<float> inputToInputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4140 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
4141
4142 std::vector<float> inputToForgetWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4143 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
4144
4145 std::vector<float> inputToCellWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4146 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
4147
4148 std::vector<float> inputToOutputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4149 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
4150
4151 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
4152 std::vector<float> inputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4153 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
4154
4155 std::vector<float> forgetGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4156 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
4157
4158 std::vector<float> cellBiasData(tensorInfo20.GetNumElements(), 0.0f);
4159 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
4160
4161 std::vector<float> outputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4162 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
4163
4164 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
4165 std::vector<float> recurrentToInputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4166 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
4167
4168 std::vector<float> recurrentToForgetWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4169 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
4170
4171 std::vector<float> recurrentToCellWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4172 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
4173
4174 std::vector<float> recurrentToOutputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4175 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
4176
4177 std::vector<float> cellToInputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4178 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
4179
4180 std::vector<float> cellToForgetWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4181 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
4182
4183 std::vector<float> cellToOutputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4184 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
4185
4186 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
4187 std::vector<float> projectionWeightsData(tensorInfo16x20.GetNumElements(), 0.0f);
4188 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
4189
4190 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
4191 std::vector<float> projectionBiasData(outputSize, 0.0f);
4192 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
4193
4194 armnn::LstmInputParams params;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004195 params.m_InputToForgetWeights = &inputToForgetWeights;
4196 params.m_InputToCellWeights = &inputToCellWeights;
4197 params.m_InputToOutputWeights = &inputToOutputWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004198 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004199 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004200 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004201 params.m_ForgetGateBias = &forgetGateBias;
4202 params.m_CellBias = &cellBias;
4203 params.m_OutputGateBias = &outputGateBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004204
4205 // additional params because: descriptor.m_CifgEnabled = false
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004206 params.m_InputToInputWeights = &inputToInputWeights;
4207 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4208 params.m_CellToInputWeights = &cellToInputWeights;
4209 params.m_InputGateBias = &inputGateBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004210
4211 // additional params because: descriptor.m_ProjectionEnabled = true
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004212 params.m_ProjectionWeights = &projectionWeights;
4213 params.m_ProjectionBias = &projectionBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004214
4215 // additional params because: descriptor.m_PeepholeEnabled = true
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004216 params.m_CellToForgetWeights = &cellToForgetWeights;
4217 params.m_CellToOutputWeights = &cellToOutputWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004218
4219 const std::string layerName("lstm");
4220 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
4221 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
4222 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
4223 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
4224
Jan Eilersf8c62972019-07-17 11:07:49 +01004225 VerifyLstmLayer checker(
4226 layerName,
4227 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
4228 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4229 descriptor,
4230 params);
4231 deserializedNetwork->Accept(checker);
4232}
Jan Eilers5b01a892019-07-23 09:47:43 +01004233class VerifyQuantizedLstmLayer : public LayerVerifierBase
4234{
4235
4236public:
4237 VerifyQuantizedLstmLayer(const std::string& layerName,
4238 const std::vector<armnn::TensorInfo>& inputInfos,
4239 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01004240 const armnn::QuantizedLstmInputParams& inputParams)
4241 : LayerVerifierBase(layerName, inputInfos, outputInfos), m_InputParams(inputParams) {}
Jan Eilers5b01a892019-07-23 09:47:43 +01004242
4243 void VisitQuantizedLstmLayer(const armnn::IConnectableLayer* layer,
4244 const armnn::QuantizedLstmInputParams& params,
4245 const char* name)
4246 {
4247 VerifyNameAndConnections(layer, name);
4248 VerifyInputParameters(params);
4249 }
4250
4251protected:
4252 void VerifyInputParameters(const armnn::QuantizedLstmInputParams& params)
4253 {
4254 VerifyConstTensors("m_InputToInputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004255 m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004256 VerifyConstTensors("m_InputToForgetWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004257 m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004258 VerifyConstTensors("m_InputToCellWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004259 m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004260 VerifyConstTensors("m_InputToOutputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004261 m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004262 VerifyConstTensors("m_RecurrentToInputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004263 m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004264 VerifyConstTensors("m_RecurrentToForgetWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004265 m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004266 VerifyConstTensors("m_RecurrentToCellWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004267 m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004268 VerifyConstTensors("m_RecurrentToOutputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004269 m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004270 VerifyConstTensors("m_InputGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004271 m_InputParams.m_InputGateBias, params.m_InputGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004272 VerifyConstTensors("m_ForgetGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004273 m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004274 VerifyConstTensors("m_CellBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004275 m_InputParams.m_CellBias, params.m_CellBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004276 VerifyConstTensors("m_OutputGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004277 m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004278 }
4279
4280private:
4281 armnn::QuantizedLstmInputParams m_InputParams;
4282};
4283
4284BOOST_AUTO_TEST_CASE(SerializeDeserializeQuantizedLstm)
4285{
4286 const uint32_t batchSize = 1;
4287 const uint32_t inputSize = 2;
4288 const uint32_t numUnits = 4;
4289 const uint32_t outputSize = numUnits;
4290
alanhsu567886324fc2019-10-25 23:44:16 +08004291 // Scale/Offset for input/output, cellState In/Out, weights, bias
4292 float inputOutputScale = 0.0078125f;
4293 int32_t inputOutputOffset = 128;
Jan Eilers5b01a892019-07-23 09:47:43 +01004294
alanhsu567886324fc2019-10-25 23:44:16 +08004295 float cellStateScale = 0.00048828125f;
4296 int32_t cellStateOffset = 0;
Jan Eilers5b01a892019-07-23 09:47:43 +01004297
alanhsu567886324fc2019-10-25 23:44:16 +08004298 float weightsScale = 0.00408021f;
4299 int32_t weightsOffset = 100;
Jan Eilers5b01a892019-07-23 09:47:43 +01004300
alanhsu567886324fc2019-10-25 23:44:16 +08004301 float biasScale = 3.1876640625e-05f;
4302 int32_t biasOffset = 0;
Jan Eilers5b01a892019-07-23 09:47:43 +01004303
alanhsu567886324fc2019-10-25 23:44:16 +08004304 // The shape of weight data is {outputSize, inputSize} = {4, 2}
4305 armnn::TensorShape inputToInputWeightsShape = {4, 2};
4306 std::vector<uint8_t> inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4307 armnn::TensorInfo inputToInputWeightsInfo(inputToInputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004308 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004309 weightsScale,
4310 weightsOffset);
4311 armnn::ConstTensor inputToInputWeights(inputToInputWeightsInfo, inputToInputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004312
alanhsu567886324fc2019-10-25 23:44:16 +08004313 armnn::TensorShape inputToForgetWeightsShape = {4, 2};
4314 std::vector<uint8_t> inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4315 armnn::TensorInfo inputToForgetWeightsInfo(inputToForgetWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004316 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004317 weightsScale,
4318 weightsOffset);
4319 armnn::ConstTensor inputToForgetWeights(inputToForgetWeightsInfo, inputToForgetWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004320
alanhsu567886324fc2019-10-25 23:44:16 +08004321 armnn::TensorShape inputToCellWeightsShape = {4, 2};
4322 std::vector<uint8_t> inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4323 armnn::TensorInfo inputToCellWeightsInfo(inputToCellWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004324 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004325 weightsScale,
4326 weightsOffset);
4327 armnn::ConstTensor inputToCellWeights(inputToCellWeightsInfo, inputToCellWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004328
alanhsu567886324fc2019-10-25 23:44:16 +08004329 armnn::TensorShape inputToOutputWeightsShape = {4, 2};
4330 std::vector<uint8_t> inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4331 armnn::TensorInfo inputToOutputWeightsInfo(inputToOutputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004332 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004333 weightsScale,
4334 weightsOffset);
4335 armnn::ConstTensor inputToOutputWeights(inputToOutputWeightsInfo, inputToOutputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004336
alanhsu567886324fc2019-10-25 23:44:16 +08004337 // The shape of recurrent weight data is {outputSize, outputSize} = {4, 4}
4338 armnn::TensorShape recurrentToInputWeightsShape = {4, 4};
4339 std::vector<uint8_t> recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4340 armnn::TensorInfo recurrentToInputWeightsInfo(recurrentToInputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004341 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004342 weightsScale,
4343 weightsOffset);
4344 armnn::ConstTensor recurrentToInputWeights(recurrentToInputWeightsInfo, recurrentToInputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004345
alanhsu567886324fc2019-10-25 23:44:16 +08004346 armnn::TensorShape recurrentToForgetWeightsShape = {4, 4};
4347 std::vector<uint8_t> recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4348 armnn::TensorInfo recurrentToForgetWeightsInfo(recurrentToForgetWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004349 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004350 weightsScale,
4351 weightsOffset);
4352 armnn::ConstTensor recurrentToForgetWeights(recurrentToForgetWeightsInfo, recurrentToForgetWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004353
alanhsu567886324fc2019-10-25 23:44:16 +08004354 armnn::TensorShape recurrentToCellWeightsShape = {4, 4};
4355 std::vector<uint8_t> recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4356 armnn::TensorInfo recurrentToCellWeightsInfo(recurrentToCellWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004357 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004358 weightsScale,
4359 weightsOffset);
4360 armnn::ConstTensor recurrentToCellWeights(recurrentToCellWeightsInfo, recurrentToCellWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004361
alanhsu567886324fc2019-10-25 23:44:16 +08004362 armnn::TensorShape recurrentToOutputWeightsShape = {4, 4};
4363 std::vector<uint8_t> recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4364 armnn::TensorInfo recurrentToOutputWeightsInfo(recurrentToOutputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004365 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004366 weightsScale,
4367 weightsOffset);
4368 armnn::ConstTensor recurrentToOutputWeights(recurrentToOutputWeightsInfo, recurrentToOutputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004369
alanhsu567886324fc2019-10-25 23:44:16 +08004370 // The shape of bias data is {outputSize} = {4}
4371 armnn::TensorShape inputGateBiasShape = {4};
4372 std::vector<int32_t> inputGateBiasData = {1, 2, 3, 4};
4373 armnn::TensorInfo inputGateBiasInfo(inputGateBiasShape,
4374 armnn::DataType::Signed32,
4375 biasScale,
4376 biasOffset);
4377 armnn::ConstTensor inputGateBias(inputGateBiasInfo, inputGateBiasData);
4378
4379 armnn::TensorShape forgetGateBiasShape = {4};
4380 std::vector<int32_t> forgetGateBiasData = {1, 2, 3, 4};
4381 armnn::TensorInfo forgetGateBiasInfo(forgetGateBiasShape,
4382 armnn::DataType::Signed32,
4383 biasScale,
4384 biasOffset);
4385 armnn::ConstTensor forgetGateBias(forgetGateBiasInfo, forgetGateBiasData);
4386
4387 armnn::TensorShape cellBiasShape = {4};
4388 std::vector<int32_t> cellBiasData = {1, 2, 3, 4};
4389 armnn::TensorInfo cellBiasInfo(cellBiasShape,
4390 armnn::DataType::Signed32,
4391 biasScale,
4392 biasOffset);
4393 armnn::ConstTensor cellBias(cellBiasInfo, cellBiasData);
4394
4395 armnn::TensorShape outputGateBiasShape = {4};
4396 std::vector<int32_t> outputGateBiasData = {1, 2, 3, 4};
4397 armnn::TensorInfo outputGateBiasInfo(outputGateBiasShape,
4398 armnn::DataType::Signed32,
4399 biasScale,
4400 biasOffset);
4401 armnn::ConstTensor outputGateBias(outputGateBiasInfo, outputGateBiasData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004402
4403 armnn::QuantizedLstmInputParams params;
4404 params.m_InputToInputWeights = &inputToInputWeights;
4405 params.m_InputToForgetWeights = &inputToForgetWeights;
4406 params.m_InputToCellWeights = &inputToCellWeights;
4407 params.m_InputToOutputWeights = &inputToOutputWeights;
4408 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4409 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4410 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4411 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4412 params.m_InputGateBias = &inputGateBias;
4413 params.m_ForgetGateBias = &forgetGateBias;
4414 params.m_CellBias = &cellBias;
4415 params.m_OutputGateBias = &outputGateBias;
4416
4417 armnn::INetworkPtr network = armnn::INetwork::Create();
alanhsu567886324fc2019-10-25 23:44:16 +08004418 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
Jan Eilers5b01a892019-07-23 09:47:43 +01004419 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
4420 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
4421 const std::string layerName("QuantizedLstm");
4422 armnn::IConnectableLayer* const quantizedLstmLayer = network->AddQuantizedLstmLayer(params, layerName.c_str());
alanhsu567886324fc2019-10-25 23:44:16 +08004423 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(0);
4424 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(1);
Jan Eilers5b01a892019-07-23 09:47:43 +01004425
alanhsu567886324fc2019-10-25 23:44:16 +08004426 // Connect up
4427 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004428 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004429 inputOutputScale,
4430 inputOutputOffset);
4431 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004432 armnn::DataType::QSymmS16,
alanhsu567886324fc2019-10-25 23:44:16 +08004433 cellStateScale,
4434 cellStateOffset);
4435 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004436 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004437 inputOutputScale,
4438 inputOutputOffset);
Jan Eilers5b01a892019-07-23 09:47:43 +01004439
4440 inputLayer->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(0));
4441 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
4442
4443 cellStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(1));
4444 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4445
4446 outputStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(2));
4447 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
4448
4449 quantizedLstmLayer->GetOutputSlot(0).Connect(cellStateOut->GetInputSlot(0));
4450 quantizedLstmLayer->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4451
4452 quantizedLstmLayer->GetOutputSlot(1).Connect(outputLayer->GetInputSlot(0));
4453 quantizedLstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
4454
4455 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4456 BOOST_CHECK(deserializedNetwork);
4457
alanhsu567886324fc2019-10-25 23:44:16 +08004458 VerifyQuantizedLstmLayer checker(layerName,
4459 {inputTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4460 {cellStateTensorInfo, outputStateTensorInfo},
4461 params);
Jan Eilers5b01a892019-07-23 09:47:43 +01004462
4463 deserializedNetwork->Accept(checker);
4464}
4465
James Conroy8d333182020-05-13 10:27:58 +01004466class VerifyQLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>
4467{
4468public:
4469 VerifyQLstmLayer(const std::string& layerName,
4470 const std::vector<armnn::TensorInfo>& inputInfos,
4471 const std::vector<armnn::TensorInfo>& outputInfos,
4472 const armnn::QLstmDescriptor& descriptor,
4473 const armnn::LstmInputParams& inputParams)
4474 : LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
4475 , m_InputParams(inputParams) {}
4476
4477 void VisitQLstmLayer(const armnn::IConnectableLayer* layer,
4478 const armnn::QLstmDescriptor& descriptor,
4479 const armnn::LstmInputParams& params,
4480 const char* name)
4481 {
4482 VerifyNameAndConnections(layer, name);
4483 VerifyDescriptor(descriptor);
4484 VerifyInputParameters(params);
4485 }
4486
4487protected:
4488 void VerifyInputParameters(const armnn::LstmInputParams& params)
4489 {
4490 VerifyConstTensors(
4491 "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4492 VerifyConstTensors(
4493 "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4494 VerifyConstTensors(
4495 "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4496 VerifyConstTensors(
4497 "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4498 VerifyConstTensors(
4499 "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4500 VerifyConstTensors(
4501 "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4502 VerifyConstTensors(
4503 "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4504 VerifyConstTensors(
4505 "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4506 VerifyConstTensors(
4507 "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
4508 VerifyConstTensors(
4509 "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
4510 VerifyConstTensors(
4511 "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
4512 VerifyConstTensors(
4513 "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
4514 VerifyConstTensors(
4515 "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4516 VerifyConstTensors(
4517 "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
4518 VerifyConstTensors(
4519 "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4520 VerifyConstTensors(
4521 "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
4522 VerifyConstTensors(
4523 "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
4524 VerifyConstTensors(
4525 "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
4526 VerifyConstTensors(
4527 "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
4528 VerifyConstTensors(
4529 "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
4530 VerifyConstTensors(
4531 "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
4532 }
4533
4534private:
4535 armnn::LstmInputParams m_InputParams;
4536};
4537
4538BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmBasic)
4539{
4540 armnn::QLstmDescriptor descriptor;
4541
4542 descriptor.m_CifgEnabled = true;
4543 descriptor.m_ProjectionEnabled = false;
4544 descriptor.m_PeepholeEnabled = false;
4545 descriptor.m_LayerNormEnabled = false;
4546
4547 descriptor.m_CellClip = 0.0f;
4548 descriptor.m_ProjectionClip = 0.0f;
4549
4550 descriptor.m_InputIntermediateScale = 0.00001f;
4551 descriptor.m_ForgetIntermediateScale = 0.00001f;
4552 descriptor.m_CellIntermediateScale = 0.00001f;
4553 descriptor.m_OutputIntermediateScale = 0.00001f;
4554
4555 descriptor.m_HiddenStateScale = 0.07f;
4556 descriptor.m_HiddenStateZeroPoint = 0;
4557
4558 const unsigned int numBatches = 2;
4559 const unsigned int inputSize = 5;
4560 const unsigned int outputSize = 4;
4561 const unsigned int numUnits = 4;
4562
4563 // Scale/Offset quantization info
4564 float inputScale = 0.0078f;
4565 int32_t inputOffset = 0;
4566
4567 float outputScale = 0.0078f;
4568 int32_t outputOffset = 0;
4569
4570 float cellStateScale = 3.5002e-05f;
4571 int32_t cellStateOffset = 0;
4572
4573 float weightsScale = 0.007f;
4574 int32_t weightsOffset = 0;
4575
4576 float biasScale = 3.5002e-05f / 1024;
4577 int32_t biasOffset = 0;
4578
4579 // Weights and bias tensor and quantization info
4580 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4581 armnn::DataType::QSymmS8,
4582 weightsScale,
4583 weightsOffset);
4584
4585 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4586 armnn::DataType::QSymmS8,
4587 weightsScale,
4588 weightsOffset);
4589
4590 armnn::TensorInfo biasInfo({numUnits}, armnn::DataType::Signed32, biasScale, biasOffset);
4591
4592 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4593 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4594 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4595
4596 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4597 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4598 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4599
4600 std::vector<int8_t> recurrentToForgetWeightsData =
4601 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4602 std::vector<int8_t> recurrentToCellWeightsData =
4603 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4604 std::vector<int8_t> recurrentToOutputWeightsData =
4605 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4606
4607 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4608 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4609 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4610
4611 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4612 std::vector<int32_t> cellBiasData(numUnits, 0);
4613 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4614
4615 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4616 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4617 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4618
4619 // Set up params
4620 armnn::LstmInputParams params;
4621 params.m_InputToForgetWeights = &inputToForgetWeights;
4622 params.m_InputToCellWeights = &inputToCellWeights;
4623 params.m_InputToOutputWeights = &inputToOutputWeights;
4624
4625 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4626 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4627 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4628
4629 params.m_ForgetGateBias = &forgetGateBias;
4630 params.m_CellBias = &cellBias;
4631 params.m_OutputGateBias = &outputGateBias;
4632
4633 // Create network
4634 armnn::INetworkPtr network = armnn::INetwork::Create();
4635 const std::string layerName("qLstm");
4636
4637 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4638 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4639 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4640
4641 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4642
4643 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4644 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4645 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4646
4647 // Input/Output tensor info
4648 armnn::TensorInfo inputInfo({numBatches , inputSize},
4649 armnn::DataType::QAsymmS8,
4650 inputScale,
4651 inputOffset);
4652
4653 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4654 armnn::DataType::QSymmS16,
4655 cellStateScale,
4656 cellStateOffset);
4657
4658 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4659 armnn::DataType::QAsymmS8,
4660 outputScale,
4661 outputOffset);
4662
4663 // Connect input/output slots
4664 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4665 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4666
4667 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4668 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4669
4670 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4671 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4672
4673 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4674 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4675
4676 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4677 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4678
4679 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4680 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4681
4682 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4683 BOOST_CHECK(deserializedNetwork);
4684
4685 VerifyQLstmLayer checker(layerName,
4686 {inputInfo, cellStateInfo, outputStateInfo},
4687 {outputStateInfo, cellStateInfo, outputStateInfo},
4688 descriptor,
4689 params);
4690
4691 deserializedNetwork->Accept(checker);
4692}
4693
4694BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmCifgLayerNorm)
4695{
4696 armnn::QLstmDescriptor descriptor;
4697
4698 // CIFG params are used when CIFG is disabled
4699 descriptor.m_CifgEnabled = true;
4700 descriptor.m_ProjectionEnabled = false;
4701 descriptor.m_PeepholeEnabled = false;
4702 descriptor.m_LayerNormEnabled = true;
4703
4704 descriptor.m_CellClip = 0.0f;
4705 descriptor.m_ProjectionClip = 0.0f;
4706
4707 descriptor.m_InputIntermediateScale = 0.00001f;
4708 descriptor.m_ForgetIntermediateScale = 0.00001f;
4709 descriptor.m_CellIntermediateScale = 0.00001f;
4710 descriptor.m_OutputIntermediateScale = 0.00001f;
4711
4712 descriptor.m_HiddenStateScale = 0.07f;
4713 descriptor.m_HiddenStateZeroPoint = 0;
4714
4715 const unsigned int numBatches = 2;
4716 const unsigned int inputSize = 5;
4717 const unsigned int outputSize = 4;
4718 const unsigned int numUnits = 4;
4719
4720 // Scale/Offset quantization info
4721 float inputScale = 0.0078f;
4722 int32_t inputOffset = 0;
4723
4724 float outputScale = 0.0078f;
4725 int32_t outputOffset = 0;
4726
4727 float cellStateScale = 3.5002e-05f;
4728 int32_t cellStateOffset = 0;
4729
4730 float weightsScale = 0.007f;
4731 int32_t weightsOffset = 0;
4732
4733 float layerNormScale = 3.5002e-05f;
4734 int32_t layerNormOffset = 0;
4735
4736 float biasScale = layerNormScale / 1024;
4737 int32_t biasOffset = 0;
4738
4739 // Weights and bias tensor and quantization info
4740 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4741 armnn::DataType::QSymmS8,
4742 weightsScale,
4743 weightsOffset);
4744
4745 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4746 armnn::DataType::QSymmS8,
4747 weightsScale,
4748 weightsOffset);
4749
4750 armnn::TensorInfo biasInfo({numUnits},
4751 armnn::DataType::Signed32,
4752 biasScale,
4753 biasOffset);
4754
4755 armnn::TensorInfo layerNormWeightsInfo({numUnits},
4756 armnn::DataType::QSymmS16,
4757 layerNormScale,
4758 layerNormOffset);
4759
4760 // Mandatory params
4761 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4762 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4763 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4764
4765 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4766 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4767 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4768
4769 std::vector<int8_t> recurrentToForgetWeightsData =
4770 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4771 std::vector<int8_t> recurrentToCellWeightsData =
4772 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4773 std::vector<int8_t> recurrentToOutputWeightsData =
4774 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4775
4776 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4777 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4778 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4779
4780 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4781 std::vector<int32_t> cellBiasData(numUnits, 0);
4782 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4783
4784 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4785 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4786 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4787
4788 // Layer Norm
4789 std::vector<int16_t> forgetLayerNormWeightsData =
4790 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4791 std::vector<int16_t> cellLayerNormWeightsData =
4792 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4793 std::vector<int16_t> outputLayerNormWeightsData =
4794 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4795
4796 armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
4797 armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
4798 armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
4799
4800 // Set up params
4801 armnn::LstmInputParams params;
4802
4803 // Mandatory params
4804 params.m_InputToForgetWeights = &inputToForgetWeights;
4805 params.m_InputToCellWeights = &inputToCellWeights;
4806 params.m_InputToOutputWeights = &inputToOutputWeights;
4807
4808 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4809 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4810 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4811
4812 params.m_ForgetGateBias = &forgetGateBias;
4813 params.m_CellBias = &cellBias;
4814 params.m_OutputGateBias = &outputGateBias;
4815
4816 // Layer Norm
4817 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
4818 params.m_CellLayerNormWeights = &cellLayerNormWeights;
4819 params.m_OutputLayerNormWeights = &outputLayerNormWeights;
4820
4821 // Create network
4822 armnn::INetworkPtr network = armnn::INetwork::Create();
4823 const std::string layerName("qLstm");
4824
4825 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4826 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4827 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4828
4829 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4830
4831 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4832 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4833 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4834
4835 // Input/Output tensor info
4836 armnn::TensorInfo inputInfo({numBatches , inputSize},
4837 armnn::DataType::QAsymmS8,
4838 inputScale,
4839 inputOffset);
4840
4841 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4842 armnn::DataType::QSymmS16,
4843 cellStateScale,
4844 cellStateOffset);
4845
4846 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4847 armnn::DataType::QAsymmS8,
4848 outputScale,
4849 outputOffset);
4850
4851 // Connect input/output slots
4852 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4853 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4854
4855 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4856 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4857
4858 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4859 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4860
4861 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4862 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4863
4864 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4865 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4866
4867 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4868 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4869
4870 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4871 BOOST_CHECK(deserializedNetwork);
4872
4873 VerifyQLstmLayer checker(layerName,
4874 {inputInfo, cellStateInfo, outputStateInfo},
4875 {outputStateInfo, cellStateInfo, outputStateInfo},
4876 descriptor,
4877 params);
4878
4879 deserializedNetwork->Accept(checker);
4880}
4881
4882BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmAdvanced)
4883{
4884 armnn::QLstmDescriptor descriptor;
4885
4886 descriptor.m_CifgEnabled = false;
4887 descriptor.m_ProjectionEnabled = true;
4888 descriptor.m_PeepholeEnabled = true;
4889 descriptor.m_LayerNormEnabled = true;
4890
4891 descriptor.m_CellClip = 0.1f;
4892 descriptor.m_ProjectionClip = 0.1f;
4893
4894 descriptor.m_InputIntermediateScale = 0.00001f;
4895 descriptor.m_ForgetIntermediateScale = 0.00001f;
4896 descriptor.m_CellIntermediateScale = 0.00001f;
4897 descriptor.m_OutputIntermediateScale = 0.00001f;
4898
4899 descriptor.m_HiddenStateScale = 0.07f;
4900 descriptor.m_HiddenStateZeroPoint = 0;
4901
4902 const unsigned int numBatches = 2;
4903 const unsigned int inputSize = 5;
4904 const unsigned int outputSize = 4;
4905 const unsigned int numUnits = 4;
4906
4907 // Scale/Offset quantization info
4908 float inputScale = 0.0078f;
4909 int32_t inputOffset = 0;
4910
4911 float outputScale = 0.0078f;
4912 int32_t outputOffset = 0;
4913
4914 float cellStateScale = 3.5002e-05f;
4915 int32_t cellStateOffset = 0;
4916
4917 float weightsScale = 0.007f;
4918 int32_t weightsOffset = 0;
4919
4920 float layerNormScale = 3.5002e-05f;
4921 int32_t layerNormOffset = 0;
4922
4923 float biasScale = layerNormScale / 1024;
4924 int32_t biasOffset = 0;
4925
4926 // Weights and bias tensor and quantization info
4927 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4928 armnn::DataType::QSymmS8,
4929 weightsScale,
4930 weightsOffset);
4931
4932 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4933 armnn::DataType::QSymmS8,
4934 weightsScale,
4935 weightsOffset);
4936
4937 armnn::TensorInfo biasInfo({numUnits},
4938 armnn::DataType::Signed32,
4939 biasScale,
4940 biasOffset);
4941
4942 armnn::TensorInfo peepholeWeightsInfo({numUnits},
4943 armnn::DataType::QSymmS16,
4944 weightsScale,
4945 weightsOffset);
4946
4947 armnn::TensorInfo layerNormWeightsInfo({numUnits},
4948 armnn::DataType::QSymmS16,
4949 layerNormScale,
4950 layerNormOffset);
4951
4952 armnn::TensorInfo projectionWeightsInfo({outputSize, numUnits},
4953 armnn::DataType::QSymmS8,
4954 weightsScale,
4955 weightsOffset);
4956
4957 // Mandatory params
4958 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4959 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4960 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4961
4962 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4963 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4964 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4965
4966 std::vector<int8_t> recurrentToForgetWeightsData =
4967 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4968 std::vector<int8_t> recurrentToCellWeightsData =
4969 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4970 std::vector<int8_t> recurrentToOutputWeightsData =
4971 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4972
4973 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4974 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4975 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4976
4977 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4978 std::vector<int32_t> cellBiasData(numUnits, 0);
4979 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4980
4981 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4982 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4983 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4984
4985 // CIFG
4986 std::vector<int8_t> inputToInputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4987 std::vector<int8_t> recurrentToInputWeightsData =
4988 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4989 std::vector<int32_t> inputGateBiasData(numUnits, 1);
4990
4991 armnn::ConstTensor inputToInputWeights(inputWeightsInfo, inputToInputWeightsData);
4992 armnn::ConstTensor recurrentToInputWeights(recurrentWeightsInfo, recurrentToInputWeightsData);
4993 armnn::ConstTensor inputGateBias(biasInfo, inputGateBiasData);
4994
4995 // Peephole
4996 std::vector<int16_t> cellToInputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4997 std::vector<int16_t> cellToForgetWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4998 std::vector<int16_t> cellToOutputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4999
5000 armnn::ConstTensor cellToInputWeights(peepholeWeightsInfo, cellToInputWeightsData);
5001 armnn::ConstTensor cellToForgetWeights(peepholeWeightsInfo, cellToForgetWeightsData);
5002 armnn::ConstTensor cellToOutputWeights(peepholeWeightsInfo, cellToOutputWeightsData);
5003
5004 // Projection
5005 std::vector<int8_t> projectionWeightsData = GenerateRandomData<int8_t>(projectionWeightsInfo.GetNumElements());
5006 std::vector<int32_t> projectionBiasData(outputSize, 1);
5007
5008 armnn::ConstTensor projectionWeights(projectionWeightsInfo, projectionWeightsData);
5009 armnn::ConstTensor projectionBias(biasInfo, projectionBiasData);
5010
5011 // Layer Norm
5012 std::vector<int16_t> inputLayerNormWeightsData =
5013 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5014 std::vector<int16_t> forgetLayerNormWeightsData =
5015 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5016 std::vector<int16_t> cellLayerNormWeightsData =
5017 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5018 std::vector<int16_t> outputLayerNormWeightsData =
5019 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
5020
5021 armnn::ConstTensor inputLayerNormWeights(layerNormWeightsInfo, inputLayerNormWeightsData);
5022 armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
5023 armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
5024 armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
5025
5026 // Set up params
5027 armnn::LstmInputParams params;
5028
5029 // Mandatory params
5030 params.m_InputToForgetWeights = &inputToForgetWeights;
5031 params.m_InputToCellWeights = &inputToCellWeights;
5032 params.m_InputToOutputWeights = &inputToOutputWeights;
5033
5034 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
5035 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
5036 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
5037
5038 params.m_ForgetGateBias = &forgetGateBias;
5039 params.m_CellBias = &cellBias;
5040 params.m_OutputGateBias = &outputGateBias;
5041
5042 // CIFG
5043 params.m_InputToInputWeights = &inputToInputWeights;
5044 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
5045 params.m_InputGateBias = &inputGateBias;
5046
5047 // Peephole
5048 params.m_CellToInputWeights = &cellToInputWeights;
5049 params.m_CellToForgetWeights = &cellToForgetWeights;
5050 params.m_CellToOutputWeights = &cellToOutputWeights;
5051
5052 // Projection
5053 params.m_ProjectionWeights = &projectionWeights;
5054 params.m_ProjectionBias = &projectionBias;
5055
5056 // Layer Norm
5057 params.m_InputLayerNormWeights = &inputLayerNormWeights;
5058 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
5059 params.m_CellLayerNormWeights = &cellLayerNormWeights;
5060 params.m_OutputLayerNormWeights = &outputLayerNormWeights;
5061
5062 // Create network
5063 armnn::INetworkPtr network = armnn::INetwork::Create();
5064 const std::string layerName("qLstm");
5065
5066 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
5067 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
5068 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
5069
5070 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
5071
5072 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
5073 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
5074 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
5075
5076 // Input/Output tensor info
5077 armnn::TensorInfo inputInfo({numBatches , inputSize},
5078 armnn::DataType::QAsymmS8,
5079 inputScale,
5080 inputOffset);
5081
5082 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
5083 armnn::DataType::QSymmS16,
5084 cellStateScale,
5085 cellStateOffset);
5086
5087 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
5088 armnn::DataType::QAsymmS8,
5089 outputScale,
5090 outputOffset);
5091
5092 // Connect input/output slots
5093 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
5094 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
5095
5096 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
5097 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
5098
5099 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
5100 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
5101
5102 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
5103 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
5104
5105 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
5106 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
5107
5108 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
5109 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
5110
5111 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
5112 BOOST_CHECK(deserializedNetwork);
5113
5114 VerifyQLstmLayer checker(layerName,
5115 {inputInfo, cellStateInfo, outputStateInfo},
5116 {outputStateInfo, cellStateInfo, outputStateInfo},
5117 descriptor,
5118 params);
5119
5120 deserializedNetwork->Accept(checker);
5121}
5122
Nattapat Chaimanowong30b00202019-02-20 17:31:34 +00005123BOOST_AUTO_TEST_SUITE_END()