blob: e7f93c67405caa534cb1d9e597b69fc9acb7a57a [file] [log] [blame]
Mike Kelly8c1701a2019-02-11 17:01:27 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
Mike Kelly8c1701a2019-02-11 17:01:27 +00006#include "../Serializer.hpp"
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +00007
Matthew Benthamff130e22020-01-17 11:47:42 +00008#include <armnn/Descriptors.hpp>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00009#include <armnn/INetwork.hpp>
Matthew Benthamff130e22020-01-17 11:47:42 +000010#include <armnn/TypesUtils.hpp>
11#include <armnn/LstmParams.hpp>
12#include <armnn/QuantizedLstmParams.hpp>
Derek Lamberti0028d1b2019-02-20 13:57:42 +000013#include <armnnDeserializer/IDeserializer.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000014
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +000015#include <random>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000016#include <vector>
17
Mike Kelly8c1701a2019-02-11 17:01:27 +000018#include <boost/test/unit_test.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000019
Derek Lamberti0028d1b2019-02-20 13:57:42 +000020using armnnDeserializer::IDeserializer;
Mike Kelly8c1701a2019-02-11 17:01:27 +000021
Saoirse Stewart3166c3e2019-02-18 15:24:53 +000022namespace
23{
24
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +010025#define DECLARE_LAYER_VERIFIER_CLASS(name) \
26class name##LayerVerifier : public LayerVerifierBase \
27{ \
28public: \
29 name##LayerVerifier(const std::string& layerName, \
30 const std::vector<armnn::TensorInfo>& inputInfos, \
31 const std::vector<armnn::TensorInfo>& outputInfos) \
32 : LayerVerifierBase(layerName, inputInfos, outputInfos) {} \
33\
34 void Visit##name##Layer(const armnn::IConnectableLayer* layer, const char* name) override \
35 { \
36 VerifyNameAndConnections(layer, name); \
37 } \
38};
39
40#define DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(name) \
41class name##LayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::name##Descriptor> \
42{ \
43public: \
44 name##LayerVerifier(const std::string& layerName, \
45 const std::vector<armnn::TensorInfo>& inputInfos, \
46 const std::vector<armnn::TensorInfo>& outputInfos, \
47 const armnn::name##Descriptor& descriptor) \
48 : LayerVerifierBaseWithDescriptor<armnn::name##Descriptor>( \
49 layerName, inputInfos, outputInfos, descriptor) {} \
50\
51 void Visit##name##Layer(const armnn::IConnectableLayer* layer, \
52 const armnn::name##Descriptor& descriptor, \
53 const char* name) override \
54 { \
55 VerifyNameAndConnections(layer, name); \
56 VerifyDescriptor(descriptor); \
57 } \
58};
59
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000060struct DefaultLayerVerifierPolicy
61{
Derek Lamberti859f9ce2019-12-10 22:05:21 +000062 static void Apply(const std::string)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000063 {
64 BOOST_TEST_MESSAGE("Unexpected layer found in network");
65 BOOST_TEST(false);
66 }
67};
68
69class LayerVerifierBase : public armnn::LayerVisitorBase<DefaultLayerVerifierPolicy>
70{
71public:
72 LayerVerifierBase(const std::string& layerName,
73 const std::vector<armnn::TensorInfo>& inputInfos,
74 const std::vector<armnn::TensorInfo>& outputInfos)
75 : m_LayerName(layerName)
76 , m_InputTensorInfos(inputInfos)
77 , m_OutputTensorInfos(outputInfos) {}
78
79 void VisitInputLayer(const armnn::IConnectableLayer*, armnn::LayerBindingId, const char*) override {}
80
Derek Lamberti859f9ce2019-12-10 22:05:21 +000081 void VisitOutputLayer(const armnn::IConnectableLayer*, armnn::LayerBindingId, const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000082
83protected:
84 void VerifyNameAndConnections(const armnn::IConnectableLayer* layer, const char* name)
85 {
86 BOOST_TEST(name == m_LayerName.c_str());
87
88 BOOST_TEST(layer->GetNumInputSlots() == m_InputTensorInfos.size());
89 BOOST_TEST(layer->GetNumOutputSlots() == m_OutputTensorInfos.size());
90
91 for (unsigned int i = 0; i < m_InputTensorInfos.size(); i++)
92 {
93 const armnn::IOutputSlot* connectedOutput = layer->GetInputSlot(i).GetConnection();
94 BOOST_CHECK(connectedOutput);
95
96 const armnn::TensorInfo& connectedInfo = connectedOutput->GetTensorInfo();
97 BOOST_TEST(connectedInfo.GetShape() == m_InputTensorInfos[i].GetShape());
98 BOOST_TEST(
99 GetDataTypeName(connectedInfo.GetDataType()) == GetDataTypeName(m_InputTensorInfos[i].GetDataType()));
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000100
101 BOOST_TEST(connectedInfo.GetQuantizationScale() == m_InputTensorInfos[i].GetQuantizationScale());
102 BOOST_TEST(connectedInfo.GetQuantizationOffset() == m_InputTensorInfos[i].GetQuantizationOffset());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000103 }
104
105 for (unsigned int i = 0; i < m_OutputTensorInfos.size(); i++)
106 {
107 const armnn::TensorInfo& outputInfo = layer->GetOutputSlot(i).GetTensorInfo();
108 BOOST_TEST(outputInfo.GetShape() == m_OutputTensorInfos[i].GetShape());
109 BOOST_TEST(
110 GetDataTypeName(outputInfo.GetDataType()) == GetDataTypeName(m_OutputTensorInfos[i].GetDataType()));
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000111
112 BOOST_TEST(outputInfo.GetQuantizationScale() == m_OutputTensorInfos[i].GetQuantizationScale());
113 BOOST_TEST(outputInfo.GetQuantizationOffset() == m_OutputTensorInfos[i].GetQuantizationOffset());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000114 }
115 }
116
Jan Eilers5b01a892019-07-23 09:47:43 +0100117 void VerifyConstTensors(const std::string& tensorName,
118 const armnn::ConstTensor* expectedPtr,
119 const armnn::ConstTensor* actualPtr)
120 {
121 if (expectedPtr == nullptr)
122 {
123 BOOST_CHECK_MESSAGE(actualPtr == nullptr, tensorName + " should not exist");
124 }
125 else
126 {
127 BOOST_CHECK_MESSAGE(actualPtr != nullptr, tensorName + " should have been set");
128 if (actualPtr != nullptr)
129 {
130 const armnn::TensorInfo& expectedInfo = expectedPtr->GetInfo();
131 const armnn::TensorInfo& actualInfo = actualPtr->GetInfo();
132
133 BOOST_CHECK_MESSAGE(expectedInfo.GetShape() == actualInfo.GetShape(),
134 tensorName + " shapes don't match");
135 BOOST_CHECK_MESSAGE(
136 GetDataTypeName(expectedInfo.GetDataType()) == GetDataTypeName(actualInfo.GetDataType()),
137 tensorName + " data types don't match");
138
139 BOOST_CHECK_MESSAGE(expectedPtr->GetNumBytes() == actualPtr->GetNumBytes(),
140 tensorName + " (GetNumBytes) data sizes do not match");
141 if (expectedPtr->GetNumBytes() == actualPtr->GetNumBytes())
142 {
143 //check the data is identical
144 const char* expectedData = static_cast<const char*>(expectedPtr->GetMemoryArea());
145 const char* actualData = static_cast<const char*>(actualPtr->GetMemoryArea());
146 bool same = true;
147 for (unsigned int i = 0; i < expectedPtr->GetNumBytes(); ++i)
148 {
149 same = expectedData[i] == actualData[i];
150 if (!same)
151 {
152 break;
153 }
154 }
155 BOOST_CHECK_MESSAGE(same, tensorName + " data does not match");
156 }
157 }
158 }
159 }
160
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000161private:
162 std::string m_LayerName;
163 std::vector<armnn::TensorInfo> m_InputTensorInfos;
164 std::vector<armnn::TensorInfo> m_OutputTensorInfos;
165};
166
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100167template<typename Descriptor>
168class LayerVerifierBaseWithDescriptor : public LayerVerifierBase
169{
170public:
171 LayerVerifierBaseWithDescriptor(const std::string& layerName,
172 const std::vector<armnn::TensorInfo>& inputInfos,
173 const std::vector<armnn::TensorInfo>& outputInfos,
174 const Descriptor& descriptor)
175 : LayerVerifierBase(layerName, inputInfos, outputInfos)
176 , m_Descriptor(descriptor) {}
177
178protected:
179 void VerifyDescriptor(const Descriptor& descriptor)
180 {
181 BOOST_CHECK(descriptor == m_Descriptor);
182 }
183
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100184 Descriptor m_Descriptor;
185};
186
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000187template<typename T>
188void CompareConstTensorData(const void* data1, const void* data2, unsigned int numElements)
189{
190 T typedData1 = static_cast<T>(data1);
191 T typedData2 = static_cast<T>(data2);
192 BOOST_CHECK(typedData1);
193 BOOST_CHECK(typedData2);
194
195 for (unsigned int i = 0; i < numElements; i++)
196 {
197 BOOST_TEST(typedData1[i] == typedData2[i]);
198 }
199}
200
201void CompareConstTensor(const armnn::ConstTensor& tensor1, const armnn::ConstTensor& tensor2)
202{
203 BOOST_TEST(tensor1.GetShape() == tensor2.GetShape());
204 BOOST_TEST(GetDataTypeName(tensor1.GetDataType()) == GetDataTypeName(tensor2.GetDataType()));
205
206 switch (tensor1.GetDataType())
207 {
208 case armnn::DataType::Float32:
209 CompareConstTensorData<const float*>(
210 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
211 break;
Derek Lambertif90c56d2020-01-10 17:14:08 +0000212 case armnn::DataType::QAsymmU8:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000213 case armnn::DataType::Boolean:
214 CompareConstTensorData<const uint8_t*>(
215 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
216 break;
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000217 case armnn::DataType::QSymmS8:
218 CompareConstTensorData<const int8_t*>(
219 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
220 break;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000221 case armnn::DataType::Signed32:
222 CompareConstTensorData<const int32_t*>(
223 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
224 break;
225 default:
226 // Note that Float16 is not yet implemented
227 BOOST_TEST_MESSAGE("Unexpected datatype");
228 BOOST_TEST(false);
229 }
230}
231
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000232armnn::INetworkPtr DeserializeNetwork(const std::string& serializerString)
233{
234 std::vector<std::uint8_t> const serializerVector{serializerString.begin(), serializerString.end()};
Derek Lamberti0028d1b2019-02-20 13:57:42 +0000235 return IDeserializer::Create()->CreateNetworkFromBinary(serializerVector);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000236}
237
238std::string SerializeNetwork(const armnn::INetwork& network)
239{
240 armnnSerializer::Serializer serializer;
241 serializer.Serialize(network);
242
243 std::stringstream stream;
244 serializer.SaveSerializedToStream(stream);
245
246 std::string serializerString{stream.str()};
247 return serializerString;
248}
249
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000250template<typename DataType>
251static std::vector<DataType> GenerateRandomData(size_t size)
252{
253 constexpr bool isIntegerType = std::is_integral<DataType>::value;
254 using Distribution =
255 typename std::conditional<isIntegerType,
256 std::uniform_int_distribution<DataType>,
257 std::uniform_real_distribution<DataType>>::type;
258
259 static constexpr DataType lowerLimit = std::numeric_limits<DataType>::min();
260 static constexpr DataType upperLimit = std::numeric_limits<DataType>::max();
261
262 static Distribution distribution(lowerLimit, upperLimit);
263 static std::default_random_engine generator;
264
265 std::vector<DataType> randomData(size);
266 std::generate(randomData.begin(), randomData.end(), []() { return distribution(generator); });
267
268 return randomData;
269}
270
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000271} // anonymous namespace
272
273BOOST_AUTO_TEST_SUITE(SerializerTests)
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000274
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000275BOOST_AUTO_TEST_CASE(SerializeAddition)
Mike Kelly8c1701a2019-02-11 17:01:27 +0000276{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100277 DECLARE_LAYER_VERIFIER_CLASS(Addition)
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000278
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000279 const std::string layerName("addition");
280 const armnn::TensorInfo tensorInfo({1, 2, 3}, armnn::DataType::Float32);
281
Mike Kelly8c1701a2019-02-11 17:01:27 +0000282 armnn::INetworkPtr network = armnn::INetwork::Create();
283 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
284 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000285 armnn::IConnectableLayer* const additionLayer = network->AddAdditionLayer(layerName.c_str());
286 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000287
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000288 inputLayer0->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(0));
289 inputLayer1->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(1));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000290 additionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Mike Kelly8c1701a2019-02-11 17:01:27 +0000291
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000292 inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
293 inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
294 additionLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
Jim Flynn3091b062019-02-15 14:45:04 +0000295
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000296 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000297 BOOST_CHECK(deserializedNetwork);
298
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000299 AdditionLayerVerifier verifier(layerName, {tensorInfo, tensorInfo}, {tensorInfo});
300 deserializedNetwork->Accept(verifier);
301}
Jim Flynnac25a1b2019-02-28 10:40:49 +0000302
Narumol Prangnawarat0cfcf232019-09-09 17:16:24 +0100303BOOST_AUTO_TEST_CASE(SerializeArgMinMax)
304{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100305 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(ArgMinMax)
Narumol Prangnawarat0cfcf232019-09-09 17:16:24 +0100306
307 const std::string layerName("argminmax");
308 const armnn::TensorInfo inputInfo({1, 2, 3}, armnn::DataType::Float32);
309 const armnn::TensorInfo outputInfo({1, 3}, armnn::DataType::Signed32);
310
311 armnn::ArgMinMaxDescriptor descriptor;
312 descriptor.m_Function = armnn::ArgMinMaxFunction::Max;
313 descriptor.m_Axis = 1;
314
315 armnn::INetworkPtr network = armnn::INetwork::Create();
316 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
317 armnn::IConnectableLayer* const argMinMaxLayer = network->AddArgMinMaxLayer(descriptor, layerName.c_str());
318 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
319
320 inputLayer->GetOutputSlot(0).Connect(argMinMaxLayer->GetInputSlot(0));
321 argMinMaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
322
323 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
324 argMinMaxLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
325
326 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
327 BOOST_CHECK(deserializedNetwork);
328
329 ArgMinMaxLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
330 deserializedNetwork->Accept(verifier);
331}
332
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000333BOOST_AUTO_TEST_CASE(SerializeBatchNormalization)
334{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100335 using Descriptor = armnn::BatchNormalizationDescriptor;
336 class BatchNormalizationLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000337 {
338 public:
339 BatchNormalizationLayerVerifier(const std::string& layerName,
340 const std::vector<armnn::TensorInfo>& inputInfos,
341 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100342 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000343 const armnn::ConstTensor& mean,
344 const armnn::ConstTensor& variance,
345 const armnn::ConstTensor& beta,
346 const armnn::ConstTensor& gamma)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100347 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
348 , m_Mean(mean)
349 , m_Variance(variance)
350 , m_Beta(beta)
351 , m_Gamma(gamma) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000352
353 void VisitBatchNormalizationLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100354 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000355 const armnn::ConstTensor& mean,
356 const armnn::ConstTensor& variance,
357 const armnn::ConstTensor& beta,
358 const armnn::ConstTensor& gamma,
359 const char* name) override
360 {
361 VerifyNameAndConnections(layer, name);
362 VerifyDescriptor(descriptor);
363
364 CompareConstTensor(mean, m_Mean);
365 CompareConstTensor(variance, m_Variance);
366 CompareConstTensor(beta, m_Beta);
367 CompareConstTensor(gamma, m_Gamma);
368 }
369
370 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000371 armnn::ConstTensor m_Mean;
372 armnn::ConstTensor m_Variance;
373 armnn::ConstTensor m_Beta;
374 armnn::ConstTensor m_Gamma;
375 };
376
377 const std::string layerName("batchNormalization");
378 const armnn::TensorInfo inputInfo ({ 1, 3, 3, 1 }, armnn::DataType::Float32);
379 const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
380
381 const armnn::TensorInfo meanInfo({1}, armnn::DataType::Float32);
382 const armnn::TensorInfo varianceInfo({1}, armnn::DataType::Float32);
383 const armnn::TensorInfo betaInfo({1}, armnn::DataType::Float32);
384 const armnn::TensorInfo gammaInfo({1}, armnn::DataType::Float32);
385
386 armnn::BatchNormalizationDescriptor descriptor;
387 descriptor.m_Eps = 0.0010000000475f;
388 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
389
390 std::vector<float> meanData({5.0});
391 std::vector<float> varianceData({2.0});
392 std::vector<float> betaData({1.0});
393 std::vector<float> gammaData({0.0});
394
395 armnn::ConstTensor mean(meanInfo, meanData);
396 armnn::ConstTensor variance(varianceInfo, varianceData);
397 armnn::ConstTensor beta(betaInfo, betaData);
398 armnn::ConstTensor gamma(gammaInfo, gammaData);
399
400 armnn::INetworkPtr network = armnn::INetwork::Create();
401 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
402 armnn::IConnectableLayer* const batchNormalizationLayer =
403 network->AddBatchNormalizationLayer(descriptor, mean, variance, beta, gamma, layerName.c_str());
404 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
405
406 inputLayer->GetOutputSlot(0).Connect(batchNormalizationLayer->GetInputSlot(0));
407 batchNormalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
408
409 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
410 batchNormalizationLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
411
412 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
413 BOOST_CHECK(deserializedNetwork);
414
415 BatchNormalizationLayerVerifier verifier(
416 layerName, {inputInfo}, {outputInfo}, descriptor, mean, variance, beta, gamma);
417 deserializedNetwork->Accept(verifier);
418}
419
420BOOST_AUTO_TEST_CASE(SerializeBatchToSpaceNd)
421{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100422 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(BatchToSpaceNd)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000423
424 const std::string layerName("spaceToBatchNd");
425 const armnn::TensorInfo inputInfo({4, 1, 2, 2}, armnn::DataType::Float32);
426 const armnn::TensorInfo outputInfo({1, 1, 4, 4}, armnn::DataType::Float32);
427
428 armnn::BatchToSpaceNdDescriptor desc;
429 desc.m_DataLayout = armnn::DataLayout::NCHW;
430 desc.m_BlockShape = {2, 2};
431 desc.m_Crops = {{0, 0}, {0, 0}};
432
433 armnn::INetworkPtr network = armnn::INetwork::Create();
434 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
435 armnn::IConnectableLayer* const batchToSpaceNdLayer = network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
436 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
437
438 inputLayer->GetOutputSlot(0).Connect(batchToSpaceNdLayer->GetInputSlot(0));
439 batchToSpaceNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
440
441 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
442 batchToSpaceNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
443
444 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
445 BOOST_CHECK(deserializedNetwork);
446
447 BatchToSpaceNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
448 deserializedNetwork->Accept(verifier);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000449}
450
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100451BOOST_AUTO_TEST_CASE(SerializeComparison)
452{
453 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Comparison)
454
455 const std::string layerName("comparison");
456
457 const armnn::TensorShape shape{2, 1, 2, 4};
458
459 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
460 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
461
462 armnn::ComparisonDescriptor descriptor(armnn::ComparisonOperation::NotEqual);
463
464 armnn::INetworkPtr network = armnn::INetwork::Create();
465 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
466 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
467 armnn::IConnectableLayer* const comparisonLayer = network->AddComparisonLayer(descriptor, layerName.c_str());
468 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
469
470 inputLayer0->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(0));
471 inputLayer1->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(1));
472 comparisonLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
473
474 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
475 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
476 comparisonLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
477
478 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
479 BOOST_CHECK(deserializedNetwork);
480
481 ComparisonLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo }, descriptor);
482 deserializedNetwork->Accept(verifier);
483}
484
Conor Kennedy76277882019-02-26 08:29:54 +0000485BOOST_AUTO_TEST_CASE(SerializeConstant)
486{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000487 class ConstantLayerVerifier : public LayerVerifierBase
Conor Kennedy76277882019-02-26 08:29:54 +0000488 {
489 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000490 ConstantLayerVerifier(const std::string& layerName,
491 const std::vector<armnn::TensorInfo>& inputInfos,
492 const std::vector<armnn::TensorInfo>& outputInfos,
493 const armnn::ConstTensor& layerInput)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100494 : LayerVerifierBase(layerName, inputInfos, outputInfos)
495 , m_LayerInput(layerInput) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000496
497 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
498 const armnn::ConstTensor& input,
499 const char* name) override
Conor Kennedy76277882019-02-26 08:29:54 +0000500 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000501 VerifyNameAndConnections(layer, name);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000502 CompareConstTensor(input, m_LayerInput);
Conor Kennedy76277882019-02-26 08:29:54 +0000503 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000504
Derek Lamberti859f9ce2019-12-10 22:05:21 +0000505 void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000506
507 private:
508 armnn::ConstTensor m_LayerInput;
Conor Kennedy76277882019-02-26 08:29:54 +0000509 };
510
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000511 const std::string layerName("constant");
512 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
Conor Kennedy76277882019-02-26 08:29:54 +0000513
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000514 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
515 armnn::ConstTensor constTensor(info, constantData);
Conor Kennedy76277882019-02-26 08:29:54 +0000516
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000517 armnn::INetworkPtr network(armnn::INetwork::Create());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000518 armnn::IConnectableLayer* input = network->AddInputLayer(0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000519 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000520 armnn::IConnectableLayer* add = network->AddAdditionLayer();
521 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
Conor Kennedy76277882019-02-26 08:29:54 +0000522
523 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
524 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
525 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
526
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000527 input->GetOutputSlot(0).SetTensorInfo(info);
528 constant->GetOutputSlot(0).SetTensorInfo(info);
529 add->GetOutputSlot(0).SetTensorInfo(info);
Conor Kennedy76277882019-02-26 08:29:54 +0000530
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000531 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Conor Kennedy76277882019-02-26 08:29:54 +0000532 BOOST_CHECK(deserializedNetwork);
533
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000534 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
535 deserializedNetwork->Accept(verifier);
Conor Kennedy76277882019-02-26 08:29:54 +0000536}
537
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000538BOOST_AUTO_TEST_CASE(SerializeConvolution2d)
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000539{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100540 using Descriptor = armnn::Convolution2dDescriptor;
541 class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000542 {
543 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000544 Convolution2dLayerVerifier(const std::string& layerName,
545 const std::vector<armnn::TensorInfo>& inputInfos,
546 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100547 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100548 const armnn::ConstTensor& weights,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100549 const armnn::Optional<armnn::ConstTensor>& biases)
550 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
551 , m_Weights(weights)
552 , m_Biases(biases) {}
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000553
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000554 void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100555 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100556 const armnn::ConstTensor& weights,
557 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000558 const char* name) override
559 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000560 VerifyNameAndConnections(layer, name);
561 VerifyDescriptor(descriptor);
562
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100563 // check weights
564 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000565
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100566 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100567 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100568 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
569
570 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000571 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100572 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000573 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000574 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000575
576 private:
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100577 armnn::ConstTensor m_Weights;
578 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000579 };
580
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000581 const std::string layerName("convolution2d");
582 const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
583 const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
Saoirse Stewart263829c2019-02-19 15:54:14 +0000584
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000585 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
586 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000587
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000588 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
589 armnn::ConstTensor weights(weightsInfo, weightsData);
590
591 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
592 armnn::ConstTensor biases(biasesInfo, biasesData);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000593
594 armnn::Convolution2dDescriptor descriptor;
595 descriptor.m_PadLeft = 1;
596 descriptor.m_PadRight = 1;
597 descriptor.m_PadTop = 1;
598 descriptor.m_PadBottom = 1;
599 descriptor.m_StrideX = 2;
600 descriptor.m_StrideY = 2;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100601 descriptor.m_DilationX = 2;
602 descriptor.m_DilationY = 2;
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000603 descriptor.m_BiasEnabled = true;
604 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
605
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000606 armnn::INetworkPtr network = armnn::INetwork::Create();
607 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000608 armnn::IConnectableLayer* const convLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100609 network->AddConvolution2dLayer(descriptor,
610 weights,
611 armnn::Optional<armnn::ConstTensor>(biases),
612 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000613 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000614
615 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000616 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000617
618 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000619 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
620
621 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
622 BOOST_CHECK(deserializedNetwork);
623
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000624 Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
625 deserializedNetwork->Accept(verifier);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000626}
627
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000628BOOST_AUTO_TEST_CASE(SerializeConvolution2dWithPerAxisParams)
629{
630 using Descriptor = armnn::Convolution2dDescriptor;
631 class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
632 {
633 public:
634 Convolution2dLayerVerifier(const std::string& layerName,
635 const std::vector<armnn::TensorInfo>& inputInfos,
636 const std::vector<armnn::TensorInfo>& outputInfos,
637 const Descriptor& descriptor,
638 const armnn::ConstTensor& weights,
639 const armnn::Optional<armnn::ConstTensor>& biases)
640 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
641 , m_Weights(weights)
642 , m_Biases(biases) {}
643
644 void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
645 const Descriptor& descriptor,
646 const armnn::ConstTensor& weights,
647 const armnn::Optional<armnn::ConstTensor>& biases,
648 const char* name) override
649 {
650 VerifyNameAndConnections(layer, name);
651 VerifyDescriptor(descriptor);
652
653 // check weights
654 CompareConstTensor(weights, m_Weights);
655
656 // check biases
657 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
658 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
659
660 if (biases.has_value() && m_Biases.has_value())
661 {
662 CompareConstTensor(biases.value(), m_Biases.value());
663 }
664 }
665
666 private:
667 armnn::ConstTensor m_Weights;
668 armnn::Optional<armnn::ConstTensor> m_Biases;
669 };
670
671 using namespace armnn;
672
673 const std::string layerName("convolution2dWithPerAxis");
674 const TensorInfo inputInfo ({ 1, 3, 1, 2 }, DataType::QAsymmU8, 0.55f, 128);
675 const TensorInfo outputInfo({ 1, 3, 1, 3 }, DataType::QAsymmU8, 0.75f, 128);
676
677 const std::vector<float> quantScales{ 0.75f, 0.65f, 0.85f };
678 constexpr unsigned int quantDimension = 0;
679
680 const TensorInfo kernelInfo({ 3, 1, 1, 2 }, DataType::QSymmS8, quantScales, quantDimension);
681
682 const std::vector<float> biasQuantScales{ 0.25f, 0.50f, 0.75f };
683 const TensorInfo biasInfo({ 3 }, DataType::Signed32, biasQuantScales, quantDimension);
684
685 std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
686 armnn::ConstTensor weights(kernelInfo, kernelData);
687 std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
688 armnn::ConstTensor biases(biasInfo, biasData);
689
690 Convolution2dDescriptor descriptor;
691 descriptor.m_StrideX = 1;
692 descriptor.m_StrideY = 1;
693 descriptor.m_PadLeft = 0;
694 descriptor.m_PadRight = 0;
695 descriptor.m_PadTop = 0;
696 descriptor.m_PadBottom = 0;
697 descriptor.m_BiasEnabled = true;
698 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
699
700 armnn::INetworkPtr network = armnn::INetwork::Create();
701 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
702 armnn::IConnectableLayer* const convLayer =
703 network->AddConvolution2dLayer(descriptor,
704 weights,
705 armnn::Optional<armnn::ConstTensor>(biases),
706 layerName.c_str());
707 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
708
709 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
710 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
711
712 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
713 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
714
715 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
716 BOOST_CHECK(deserializedNetwork);
717
718 Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
719 deserializedNetwork->Accept(verifier);
720}
721
Aron Virginas-Tarda9d2d32019-09-20 10:42:02 +0100722BOOST_AUTO_TEST_CASE(SerializeDepthToSpace)
723{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100724 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(DepthToSpace)
Aron Virginas-Tarda9d2d32019-09-20 10:42:02 +0100725
726 const std::string layerName("depthToSpace");
727
728 const armnn::TensorInfo inputInfo ({ 1, 8, 4, 12 }, armnn::DataType::Float32);
729 const armnn::TensorInfo outputInfo({ 1, 16, 8, 3 }, armnn::DataType::Float32);
730
731 armnn::DepthToSpaceDescriptor desc;
732 desc.m_BlockSize = 2;
733 desc.m_DataLayout = armnn::DataLayout::NHWC;
734
735 armnn::INetworkPtr network = armnn::INetwork::Create();
736 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
737 armnn::IConnectableLayer* const depthToSpaceLayer = network->AddDepthToSpaceLayer(desc, layerName.c_str());
738 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
739
740 inputLayer->GetOutputSlot(0).Connect(depthToSpaceLayer->GetInputSlot(0));
741 depthToSpaceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
742
743 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
744 depthToSpaceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
745
746 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
747 BOOST_CHECK(deserializedNetwork);
748
749 DepthToSpaceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
750 deserializedNetwork->Accept(verifier);
751}
752
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000753BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2d)
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000754{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100755 using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
756 class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000757 {
758 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000759 DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
760 const std::vector<armnn::TensorInfo>& inputInfos,
761 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100762 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100763 const armnn::ConstTensor& weights,
764 const armnn::Optional<armnn::ConstTensor>& biases) :
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100765 LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100766 m_Weights(weights),
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100767 m_Biases(biases) {}
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000768
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000769 void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100770 const Descriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100771 const armnn::ConstTensor& weights,
772 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000773 const char* name) override
774 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000775 VerifyNameAndConnections(layer, name);
776 VerifyDescriptor(descriptor);
777
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100778 // check weights
779 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000780
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100781 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100782 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100783 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
784
785 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000786 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100787 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000788 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000789 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000790
791 private:
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100792 armnn::ConstTensor m_Weights;
793 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000794 };
795
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000796 const std::string layerName("depwiseConvolution2d");
797 const armnn::TensorInfo inputInfo ({ 1, 5, 5, 3 }, armnn::DataType::Float32);
798 const armnn::TensorInfo outputInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000799
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000800 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
801 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000802
803 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
804 armnn::ConstTensor weights(weightsInfo, weightsData);
805
806 std::vector<int32_t> biasesData = GenerateRandomData<int32_t>(biasesInfo.GetNumElements());
807 armnn::ConstTensor biases(biasesInfo, biasesData);
808
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000809 armnn::DepthwiseConvolution2dDescriptor descriptor;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100810 descriptor.m_PadLeft = 1;
811 descriptor.m_PadRight = 1;
812 descriptor.m_PadTop = 1;
813 descriptor.m_PadBottom = 1;
814 descriptor.m_StrideX = 2;
815 descriptor.m_StrideY = 2;
816 descriptor.m_DilationX = 2;
817 descriptor.m_DilationY = 2;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000818 descriptor.m_BiasEnabled = true;
819 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
820
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000821 armnn::INetworkPtr network = armnn::INetwork::Create();
822 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
823 armnn::IConnectableLayer* const depthwiseConvLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100824 network->AddDepthwiseConvolution2dLayer(descriptor,
825 weights,
826 armnn::Optional<armnn::ConstTensor>(biases),
827 layerName.c_str());
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000828 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
829
830 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000831 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000832
833 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000834 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
835
836 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
837 BOOST_CHECK(deserializedNetwork);
838
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000839 DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
840 deserializedNetwork->Accept(verifier);
Jim Flynn18ce3382019-03-08 11:08:30 +0000841}
842
Sadik Armagan1a84fe32020-03-27 15:56:57 +0000843BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2dWithPerAxisParams)
844{
845 using Descriptor = armnn::DepthwiseConvolution2dDescriptor;
846 class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
847 {
848 public:
849 DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
850 const std::vector<armnn::TensorInfo>& inputInfos,
851 const std::vector<armnn::TensorInfo>& outputInfos,
852 const Descriptor& descriptor,
853 const armnn::ConstTensor& weights,
854 const armnn::Optional<armnn::ConstTensor>& biases) :
855 LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor),
856 m_Weights(weights),
857 m_Biases(biases) {}
858
859 void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
860 const Descriptor& descriptor,
861 const armnn::ConstTensor& weights,
862 const armnn::Optional<armnn::ConstTensor>& biases,
863 const char* name) override
864 {
865 VerifyNameAndConnections(layer, name);
866 VerifyDescriptor(descriptor);
867
868 // check weights
869 CompareConstTensor(weights, m_Weights);
870
871 // check biases
872 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
873 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
874
875 if (biases.has_value() && m_Biases.has_value())
876 {
877 CompareConstTensor(biases.value(), m_Biases.value());
878 }
879 }
880
881 private:
882 armnn::ConstTensor m_Weights;
883 armnn::Optional<armnn::ConstTensor> m_Biases;
884 };
885
886 using namespace armnn;
887
888 const std::string layerName("depwiseConvolution2dWithPerAxis");
889 const TensorInfo inputInfo ({ 1, 3, 3, 2 }, DataType::QAsymmU8, 0.55f, 128);
890 const TensorInfo outputInfo({ 1, 2, 2, 4 }, DataType::QAsymmU8, 0.75f, 128);
891
892 const std::vector<float> quantScales{ 0.75f, 0.80f, 0.90f, 0.95f };
893 const unsigned int quantDimension = 0;
894 TensorInfo kernelInfo({ 2, 2, 2, 2 }, DataType::QSymmS8, quantScales, quantDimension);
895
896 const std::vector<float> biasQuantScales{ 0.25f, 0.35f, 0.45f, 0.55f };
897 constexpr unsigned int biasQuantDimension = 0;
898 TensorInfo biasInfo({ 4 }, DataType::Signed32, biasQuantScales, biasQuantDimension);
899
900 std::vector<int8_t> kernelData = GenerateRandomData<int8_t>(kernelInfo.GetNumElements());
901 armnn::ConstTensor weights(kernelInfo, kernelData);
902 std::vector<int32_t> biasData = GenerateRandomData<int32_t>(biasInfo.GetNumElements());
903 armnn::ConstTensor biases(biasInfo, biasData);
904
905 DepthwiseConvolution2dDescriptor descriptor;
906 descriptor.m_StrideX = 1;
907 descriptor.m_StrideY = 1;
908 descriptor.m_PadLeft = 0;
909 descriptor.m_PadRight = 0;
910 descriptor.m_PadTop = 0;
911 descriptor.m_PadBottom = 0;
912 descriptor.m_DilationX = 1;
913 descriptor.m_DilationY = 1;
914 descriptor.m_BiasEnabled = true;
915 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
916
917 armnn::INetworkPtr network = armnn::INetwork::Create();
918 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
919 armnn::IConnectableLayer* const depthwiseConvLayer =
920 network->AddDepthwiseConvolution2dLayer(descriptor,
921 weights,
922 armnn::Optional<armnn::ConstTensor>(biases),
923 layerName.c_str());
924 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
925
926 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
927 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
928
929 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
930 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
931
932 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
933 BOOST_CHECK(deserializedNetwork);
934
935 DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
936 deserializedNetwork->Accept(verifier);
937}
938
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000939BOOST_AUTO_TEST_CASE(SerializeDequantize)
940{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100941 DECLARE_LAYER_VERIFIER_CLASS(Dequantize)
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000942
943 const std::string layerName("dequantize");
Derek Lambertif90c56d2020-01-10 17:14:08 +0000944 const armnn::TensorInfo inputInfo({ 1, 5, 2, 3 }, armnn::DataType::QAsymmU8, 0.5f, 1);
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000945 const armnn::TensorInfo outputInfo({ 1, 5, 2, 3 }, armnn::DataType::Float32);
946
947 armnn::INetworkPtr network = armnn::INetwork::Create();
948 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
949 armnn::IConnectableLayer* const dequantizeLayer = network->AddDequantizeLayer(layerName.c_str());
950 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
951
952 inputLayer->GetOutputSlot(0).Connect(dequantizeLayer->GetInputSlot(0));
953 dequantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
954
955 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
956 dequantizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
957
958 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
959 BOOST_CHECK(deserializedNetwork);
960
961 DequantizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
962 deserializedNetwork->Accept(verifier);
963}
964
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000965BOOST_AUTO_TEST_CASE(SerializeDeserializeDetectionPostProcess)
966{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100967 using Descriptor = armnn::DetectionPostProcessDescriptor;
968 class DetectionPostProcessLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000969 {
970 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000971 DetectionPostProcessLayerVerifier(const std::string& layerName,
972 const std::vector<armnn::TensorInfo>& inputInfos,
973 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100974 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000975 const armnn::ConstTensor& anchors)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100976 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
977 , m_Anchors(anchors) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000978
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000979 void VisitDetectionPostProcessLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +0100980 const Descriptor& descriptor,
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000981 const armnn::ConstTensor& anchors,
982 const char* name) override
983 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000984 VerifyNameAndConnections(layer, name);
985 VerifyDescriptor(descriptor);
986
987 CompareConstTensor(anchors, m_Anchors);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000988 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000989
990 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000991 armnn::ConstTensor m_Anchors;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000992 };
993
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000994 const std::string layerName("detectionPostProcess");
995
996 const std::vector<armnn::TensorInfo> inputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000997 armnn::TensorInfo({ 1, 6, 4 }, armnn::DataType::Float32),
998 armnn::TensorInfo({ 1, 6, 3}, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000999 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001000
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001001 const std::vector<armnn::TensorInfo> outputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001002 armnn::TensorInfo({ 1, 3, 4 }, armnn::DataType::Float32),
1003 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1004 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
1005 armnn::TensorInfo({ 1 }, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001006 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001007
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001008 armnn::DetectionPostProcessDescriptor descriptor;
1009 descriptor.m_UseRegularNms = true;
1010 descriptor.m_MaxDetections = 3;
1011 descriptor.m_MaxClassesPerDetection = 1;
1012 descriptor.m_DetectionsPerClass =1;
1013 descriptor.m_NmsScoreThreshold = 0.0;
1014 descriptor.m_NmsIouThreshold = 0.5;
1015 descriptor.m_NumClasses = 2;
1016 descriptor.m_ScaleY = 10.0;
1017 descriptor.m_ScaleX = 10.0;
1018 descriptor.m_ScaleH = 5.0;
1019 descriptor.m_ScaleW = 5.0;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001020
1021 const armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32);
1022 const std::vector<float> anchorsData({
1023 0.5f, 0.5f, 1.0f, 1.0f,
1024 0.5f, 0.5f, 1.0f, 1.0f,
1025 0.5f, 0.5f, 1.0f, 1.0f,
1026 0.5f, 10.5f, 1.0f, 1.0f,
1027 0.5f, 10.5f, 1.0f, 1.0f,
1028 0.5f, 100.5f, 1.0f, 1.0f
1029 });
1030 armnn::ConstTensor anchors(anchorsInfo, anchorsData);
1031
1032 armnn::INetworkPtr network = armnn::INetwork::Create();
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001033 armnn::IConnectableLayer* const detectionLayer =
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001034 network->AddDetectionPostProcessLayer(descriptor, anchors, layerName.c_str());
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001035
1036 for (unsigned int i = 0; i < 2; i++)
1037 {
1038 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(static_cast<int>(i));
1039 inputLayer->GetOutputSlot(0).Connect(detectionLayer->GetInputSlot(i));
1040 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfos[i]);
1041 }
1042
1043 for (unsigned int i = 0; i < 4; i++)
1044 {
1045 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(static_cast<int>(i));
1046 detectionLayer->GetOutputSlot(i).Connect(outputLayer->GetInputSlot(0));
1047 detectionLayer->GetOutputSlot(i).SetTensorInfo(outputInfos[i]);
1048 }
1049
1050 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1051 BOOST_CHECK(deserializedNetwork);
1052
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001053 DetectionPostProcessLayerVerifier verifier(layerName, inputInfos, outputInfos, descriptor, anchors);
1054 deserializedNetwork->Accept(verifier);
1055}
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00001056
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001057BOOST_AUTO_TEST_CASE(SerializeDivision)
1058{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001059 DECLARE_LAYER_VERIFIER_CLASS(Division)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001060
1061 const std::string layerName("division");
1062 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1063
1064 armnn::INetworkPtr network = armnn::INetwork::Create();
1065 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1066 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1067 armnn::IConnectableLayer* const divisionLayer = network->AddDivisionLayer(layerName.c_str());
1068 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1069
1070 inputLayer0->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(0));
1071 inputLayer1->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(1));
1072 divisionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1073
1074 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1075 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1076 divisionLayer->GetOutputSlot(0).SetTensorInfo(info);
1077
1078 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1079 BOOST_CHECK(deserializedNetwork);
1080
1081 DivisionLayerVerifier verifier(layerName, {info, info}, {info});
1082 deserializedNetwork->Accept(verifier);
1083}
1084
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001085class EqualLayerVerifier : public LayerVerifierBase
1086{
1087public:
1088 EqualLayerVerifier(const std::string& layerName,
1089 const std::vector<armnn::TensorInfo>& inputInfos,
1090 const std::vector<armnn::TensorInfo>& outputInfos)
1091 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1092
1093 void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1094 const armnn::ComparisonDescriptor& descriptor,
1095 const char* name) override
1096 {
1097 VerifyNameAndConnections(layer, name);
1098 BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Equal);
1099 }
1100
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001101 void VisitEqualLayer(const armnn::IConnectableLayer*, const char*) override
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001102 {
1103 throw armnn::Exception("EqualLayer should have translated to ComparisonLayer");
1104 }
1105};
1106
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001107// NOTE: Until the deprecated AddEqualLayer disappears this test checks that calling
1108// AddEqualLayer places a ComparisonLayer into the serialized format and that
1109// when this deserialises we have a ComparisonLayer
1110BOOST_AUTO_TEST_CASE(SerializeEqual)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001111{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001112 const std::string layerName("equal");
1113
1114 const armnn::TensorShape shape{2, 1, 2, 4};
1115
1116 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1117 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1118
1119 armnn::INetworkPtr network = armnn::INetwork::Create();
1120 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1121 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1122 ARMNN_NO_DEPRECATE_WARN_BEGIN
1123 armnn::IConnectableLayer* const equalLayer = network->AddEqualLayer(layerName.c_str());
1124 ARMNN_NO_DEPRECATE_WARN_END
1125 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1126
1127 inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1128 inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1129 equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1130
1131 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1132 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1133 equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1134
1135 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1136 BOOST_CHECK(deserializedNetwork);
1137
1138 EqualLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1139 deserializedNetwork->Accept(verifier);
1140}
1141
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001142BOOST_AUTO_TEST_CASE(EnsureEqualBackwardCompatibility)
1143{
1144 // The hex data below is a flat buffer containing a simple network with two inputs,
1145 // an EqualLayer (now deprecated) and an output
1146 //
1147 // This test verifies that we can still deserialize this old-style model by replacing
1148 // the EqualLayer with an equivalent ComparisonLayer
1149 const std::vector<uint8_t> equalModel =
1150 {
1151 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1152 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1153 0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1155 0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1156 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1157 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1159 0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1160 0x00, 0x13, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1161 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1162 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x65, 0x71, 0x75, 0x61, 0x6C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1163 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1164 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1165 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
1166 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1167 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1168 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1169 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1170 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1171 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1172 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1173 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1175 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1176 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1177 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
1178 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1179 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1180 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1181 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1182 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1183 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1184 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1185 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1186 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1187 0x04, 0x00, 0x00, 0x00
1188 };
1189
1190 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(equalModel.begin(), equalModel.end()));
1191 BOOST_CHECK(deserializedNetwork);
1192
1193 const armnn::TensorShape shape{ 2, 1, 2, 4 };
1194
1195 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1196 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1197
1198 EqualLayerVerifier verifier("equal", { inputInfo, inputInfo }, { outputInfo });
1199 deserializedNetwork->Accept(verifier);
1200}
1201
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001202BOOST_AUTO_TEST_CASE(SerializeFloor)
1203{
1204 DECLARE_LAYER_VERIFIER_CLASS(Floor)
1205
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001206 const std::string layerName("floor");
1207 const armnn::TensorInfo info({4,4}, armnn::DataType::Float32);
1208
1209 armnn::INetworkPtr network = armnn::INetwork::Create();
1210 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1211 armnn::IConnectableLayer* const floorLayer = network->AddFloorLayer(layerName.c_str());
1212 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1213
1214 inputLayer->GetOutputSlot(0).Connect(floorLayer->GetInputSlot(0));
1215 floorLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1216
1217 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1218 floorLayer->GetOutputSlot(0).SetTensorInfo(info);
1219
1220 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1221 BOOST_CHECK(deserializedNetwork);
1222
1223 FloorLayerVerifier verifier(layerName, {info}, {info});
1224 deserializedNetwork->Accept(verifier);
1225}
1226
1227BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
1228{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001229 using Descriptor = armnn::FullyConnectedDescriptor;
1230 class FullyConnectedLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001231 {
1232 public:
1233 FullyConnectedLayerVerifier(const std::string& layerName,
1234 const std::vector<armnn::TensorInfo>& inputInfos,
1235 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001236 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001237 const armnn::ConstTensor& weight,
1238 const armnn::Optional<armnn::ConstTensor>& bias)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001239 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
1240 , m_Weight(weight)
1241 , m_Bias(bias) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001242
1243 void VisitFullyConnectedLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001244 const Descriptor& descriptor,
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001245 const armnn::ConstTensor& weight,
1246 const armnn::Optional<armnn::ConstTensor>& bias,
1247 const char* name) override
1248 {
1249 VerifyNameAndConnections(layer, name);
1250 VerifyDescriptor(descriptor);
1251
1252 CompareConstTensor(weight, m_Weight);
1253
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001254 BOOST_TEST(bias.has_value() == descriptor.m_BiasEnabled);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001255 BOOST_TEST(bias.has_value() == m_Bias.has_value());
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001256
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001257 if (bias.has_value() && m_Bias.has_value())
1258 {
1259 CompareConstTensor(bias.value(), m_Bias.value());
1260 }
1261 }
1262
1263 private:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001264 armnn::ConstTensor m_Weight;
1265 armnn::Optional<armnn::ConstTensor> m_Bias;
1266 };
1267
1268 const std::string layerName("fullyConnected");
1269 const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
1270 const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
1271
1272 const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
1273 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
1274 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
1275 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
1276 armnn::ConstTensor weights(weightsInfo, weightsData);
1277 armnn::ConstTensor biases(biasesInfo, biasesData);
1278
1279 armnn::FullyConnectedDescriptor descriptor;
1280 descriptor.m_BiasEnabled = true;
1281 descriptor.m_TransposeWeightMatrix = false;
1282
1283 armnn::INetworkPtr network = armnn::INetwork::Create();
1284 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1285 armnn::IConnectableLayer* const fullyConnectedLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +01001286 network->AddFullyConnectedLayer(descriptor,
1287 weights,
1288 armnn::Optional<armnn::ConstTensor>(biases),
1289 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001290 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1291
1292 inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
1293 fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1294
1295 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1296 fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1297
1298 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1299 BOOST_CHECK(deserializedNetwork);
1300
1301 FullyConnectedLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
1302 deserializedNetwork->Accept(verifier);
1303}
1304
1305BOOST_AUTO_TEST_CASE(SerializeGather)
1306{
1307 class GatherLayerVerifier : public LayerVerifierBase
1308 {
1309 public:
1310 GatherLayerVerifier(const std::string& layerName,
1311 const std::vector<armnn::TensorInfo>& inputInfos,
1312 const std::vector<armnn::TensorInfo>& outputInfos)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001313 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001314
1315 void VisitGatherLayer(const armnn::IConnectableLayer* layer, const char *name) override
1316 {
1317 VerifyNameAndConnections(layer, name);
1318 }
1319
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001320 void VisitConstantLayer(const armnn::IConnectableLayer*,
1321 const armnn::ConstTensor&,
1322 const char*) override {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001323 };
1324
1325 const std::string layerName("gather");
Derek Lambertif90c56d2020-01-10 17:14:08 +00001326 armnn::TensorInfo paramsInfo({ 8 }, armnn::DataType::QAsymmU8);
1327 armnn::TensorInfo outputInfo({ 3 }, armnn::DataType::QAsymmU8);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001328 const armnn::TensorInfo indicesInfo({ 3 }, armnn::DataType::Signed32);
1329
1330 paramsInfo.SetQuantizationScale(1.0f);
1331 paramsInfo.SetQuantizationOffset(0);
1332 outputInfo.SetQuantizationScale(1.0f);
1333 outputInfo.SetQuantizationOffset(0);
1334
1335 const std::vector<int32_t>& indicesData = {7, 6, 5};
1336
1337 armnn::INetworkPtr network = armnn::INetwork::Create();
1338 armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
1339 armnn::IConnectableLayer *const constantLayer =
1340 network->AddConstantLayer(armnn::ConstTensor(indicesInfo, indicesData));
1341 armnn::IConnectableLayer *const gatherLayer = network->AddGatherLayer(layerName.c_str());
1342 armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
1343
1344 inputLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(0));
1345 constantLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(1));
1346 gatherLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1347
1348 inputLayer->GetOutputSlot(0).SetTensorInfo(paramsInfo);
1349 constantLayer->GetOutputSlot(0).SetTensorInfo(indicesInfo);
1350 gatherLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1351
1352 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1353 BOOST_CHECK(deserializedNetwork);
1354
1355 GatherLayerVerifier verifier(layerName, {paramsInfo, indicesInfo}, {outputInfo});
1356 deserializedNetwork->Accept(verifier);
1357}
1358
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001359class GreaterLayerVerifier : public LayerVerifierBase
1360{
1361public:
1362 GreaterLayerVerifier(const std::string& layerName,
1363 const std::vector<armnn::TensorInfo>& inputInfos,
1364 const std::vector<armnn::TensorInfo>& outputInfos)
1365 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1366
1367 void VisitComparisonLayer(const armnn::IConnectableLayer* layer,
1368 const armnn::ComparisonDescriptor& descriptor,
1369 const char* name) override
1370 {
1371 VerifyNameAndConnections(layer, name);
1372 BOOST_CHECK(descriptor.m_Operation == armnn::ComparisonOperation::Greater);
1373 }
1374
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001375 void VisitGreaterLayer(const armnn::IConnectableLayer*, const char*) override
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001376 {
1377 throw armnn::Exception("GreaterLayer should have translated to ComparisonLayer");
1378 }
1379};
1380
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001381// NOTE: Until the deprecated AddGreaterLayer disappears this test checks that calling
1382// AddGreaterLayer places a ComparisonLayer into the serialized format and that
1383// when this deserialises we have a ComparisonLayer
1384BOOST_AUTO_TEST_CASE(SerializeGreater)
Aron Virginas-Tar781ced92019-10-03 11:15:39 +01001385{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001386 const std::string layerName("greater");
1387
1388 const armnn::TensorShape shape{2, 1, 2, 4};
1389
1390 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1391 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1392
1393 armnn::INetworkPtr network = armnn::INetwork::Create();
1394 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1395 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1396 ARMNN_NO_DEPRECATE_WARN_BEGIN
1397 armnn::IConnectableLayer* const equalLayer = network->AddGreaterLayer(layerName.c_str());
1398 ARMNN_NO_DEPRECATE_WARN_END
1399 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1400
1401 inputLayer0->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1402 inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1403 equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1404
1405 inputLayer0->GetOutputSlot(0).SetTensorInfo(inputInfo);
1406 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputInfo);
1407 equalLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1408
1409 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1410 BOOST_CHECK(deserializedNetwork);
1411
1412 GreaterLayerVerifier verifier(layerName, { inputInfo, inputInfo }, { outputInfo });
1413 deserializedNetwork->Accept(verifier);
1414}
1415
Aron Virginas-Tar6d2e6592019-10-22 11:44:47 +01001416BOOST_AUTO_TEST_CASE(EnsureGreaterBackwardCompatibility)
1417{
1418 // The hex data below is a flat buffer containing a simple network with two inputs,
1419 // an GreaterLayer (now deprecated) and an output
1420 //
1421 // This test verifies that we can still deserialize this old-style model by replacing
1422 // the GreaterLayer with an equivalent ComparisonLayer
1423 const std::vector<uint8_t> greaterModel =
1424 {
1425 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1426 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1427 0xCC, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1428 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1429 0x60, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1430 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xEA, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1431 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1432 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1433 0x64, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1434 0x00, 0x19, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1435 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1436 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x00, 0x02, 0x00, 0x00, 0x00,
1437 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1438 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
1439 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1440 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1441 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1442 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1443 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1444 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1445 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1446 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1447 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1448 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1449 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1450 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1451 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1452 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1453 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1454 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1455 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1456 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1457 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1458 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1459 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1460 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1461 0x02, 0x00, 0x00, 0x00
1462 };
1463
1464 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(greaterModel.begin(), greaterModel.end()));
1465 BOOST_CHECK(deserializedNetwork);
1466
1467 const armnn::TensorShape shape{ 1, 2, 2, 2 };
1468
1469 const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
1470 const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Boolean);
1471
1472 GreaterLayerVerifier verifier("greater", { inputInfo, inputInfo }, { outputInfo });
1473 deserializedNetwork->Accept(verifier);
1474}
1475
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001476BOOST_AUTO_TEST_CASE(SerializeInstanceNormalization)
1477{
1478 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(InstanceNormalization)
1479
Aron Virginas-Tar781ced92019-10-03 11:15:39 +01001480 const std::string layerName("instanceNormalization");
1481 const armnn::TensorInfo info({ 1, 2, 1, 5 }, armnn::DataType::Float32);
1482
1483 armnn::InstanceNormalizationDescriptor descriptor;
1484 descriptor.m_Gamma = 1.1f;
1485 descriptor.m_Beta = 0.1f;
1486 descriptor.m_Eps = 0.0001f;
1487 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
1488
1489 armnn::INetworkPtr network = armnn::INetwork::Create();
1490 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1491 armnn::IConnectableLayer* const instanceNormLayer =
1492 network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1493 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1494
1495 inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1496 instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1497
1498 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1499 instanceNormLayer->GetOutputSlot(0).SetTensorInfo(info);
1500
1501 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1502 BOOST_CHECK(deserializedNetwork);
1503
1504 InstanceNormalizationLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1505 deserializedNetwork->Accept(verifier);
1506}
1507
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001508DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(L2Normalization)
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001509
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001510BOOST_AUTO_TEST_CASE(SerializeL2Normalization)
1511{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001512 const std::string l2NormLayerName("l2Normalization");
1513 const armnn::TensorInfo info({1, 2, 1, 5}, armnn::DataType::Float32);
1514
1515 armnn::L2NormalizationDescriptor desc;
1516 desc.m_DataLayout = armnn::DataLayout::NCHW;
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001517 desc.m_Eps = 0.0001f;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001518
1519 armnn::INetworkPtr network = armnn::INetwork::Create();
1520 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1521 armnn::IConnectableLayer* const l2NormLayer = network->AddL2NormalizationLayer(desc, l2NormLayerName.c_str());
1522 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1523
1524 inputLayer0->GetOutputSlot(0).Connect(l2NormLayer->GetInputSlot(0));
1525 l2NormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1526
1527 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1528 l2NormLayer->GetOutputSlot(0).SetTensorInfo(info);
1529
1530 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1531 BOOST_CHECK(deserializedNetwork);
1532
1533 L2NormalizationLayerVerifier verifier(l2NormLayerName, {info}, {info}, desc);
1534 deserializedNetwork->Accept(verifier);
1535}
1536
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001537BOOST_AUTO_TEST_CASE(EnsureL2NormalizationBackwardCompatibility)
1538{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001539 // The hex data below is a flat buffer containing a simple network with one input
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001540 // a L2Normalization layer and an output layer with dimensions as per the tensor infos below.
1541 //
1542 // This test verifies that we can still read back these old style
1543 // models without the normalization epsilon value.
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001544 const std::vector<uint8_t> l2NormalizationModel =
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001545 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001546 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1547 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1548 0x3C, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1549 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
1550 0x04, 0x00, 0x00, 0x00, 0xD6, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
1551 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
1552 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1554 0x4C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
1555 0x00, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1556 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1557 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1558 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x20, 0x00,
1559 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x6C, 0x32, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x61, 0x74,
1560 0x69, 0x6F, 0x6E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00,
1561 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1562 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
1563 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
1564 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1565 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1566 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1567 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1568 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1569 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1570 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1571 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1572 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1573 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1574 0x05, 0x00, 0x00, 0x00, 0x00
1575 };
1576
1577 armnn::INetworkPtr deserializedNetwork =
1578 DeserializeNetwork(std::string(l2NormalizationModel.begin(), l2NormalizationModel.end()));
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001579 BOOST_CHECK(deserializedNetwork);
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001580
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001581 const std::string layerName("l2Normalization");
1582 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 2, 1, 5}, armnn::DataType::Float32);
1583
1584 armnn::L2NormalizationDescriptor desc;
1585 desc.m_DataLayout = armnn::DataLayout::NCHW;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001586 // Since this variable does not exist in the l2NormalizationModel dump, the default value will be loaded
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001587 desc.m_Eps = 1e-12f;
1588
1589 L2NormalizationLayerVerifier verifier(layerName, {inputInfo}, {inputInfo}, desc);
1590 deserializedNetwork->Accept(verifier);
1591}
1592
Sadik Armagan26257852019-10-14 13:00:47 +01001593BOOST_AUTO_TEST_CASE(SerializeLogSoftmax)
1594{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001595 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(LogSoftmax)
Sadik Armagan26257852019-10-14 13:00:47 +01001596
1597 const std::string layerName("log_softmax");
1598 const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
1599
1600 armnn::LogSoftmaxDescriptor descriptor;
1601 descriptor.m_Beta = 1.0f;
1602 descriptor.m_Axis = -1;
1603
1604 armnn::INetworkPtr network = armnn::INetwork::Create();
1605 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1606 armnn::IConnectableLayer* const logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
1607 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1608
1609 inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
1610 logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1611
1612 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1613 logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
1614
1615 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1616 BOOST_CHECK(deserializedNetwork);
1617
1618 LogSoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1619 deserializedNetwork->Accept(verifier);
1620}
1621
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001622BOOST_AUTO_TEST_CASE(SerializeMaximum)
1623{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001624 DECLARE_LAYER_VERIFIER_CLASS(Maximum)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001625
1626 const std::string layerName("maximum");
1627 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1628
1629 armnn::INetworkPtr network = armnn::INetwork::Create();
1630 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1631 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1632 armnn::IConnectableLayer* const maximumLayer = network->AddMaximumLayer(layerName.c_str());
1633 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1634
1635 inputLayer0->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(0));
1636 inputLayer1->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(1));
1637 maximumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1638
1639 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1640 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1641 maximumLayer->GetOutputSlot(0).SetTensorInfo(info);
1642
1643 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1644 BOOST_CHECK(deserializedNetwork);
1645
1646 MaximumLayerVerifier verifier(layerName, {info, info}, {info});
1647 deserializedNetwork->Accept(verifier);
1648}
1649
1650BOOST_AUTO_TEST_CASE(SerializeMean)
1651{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001652 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Mean)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001653
1654 const std::string layerName("mean");
1655 const armnn::TensorInfo inputInfo({1, 1, 3, 2}, armnn::DataType::Float32);
1656 const armnn::TensorInfo outputInfo({1, 1, 1, 2}, armnn::DataType::Float32);
1657
1658 armnn::MeanDescriptor descriptor;
1659 descriptor.m_Axis = { 2 };
1660 descriptor.m_KeepDims = true;
1661
1662 armnn::INetworkPtr network = armnn::INetwork::Create();
1663 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1664 armnn::IConnectableLayer* const meanLayer = network->AddMeanLayer(descriptor, layerName.c_str());
1665 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1666
1667 inputLayer->GetOutputSlot(0).Connect(meanLayer->GetInputSlot(0));
1668 meanLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1669
1670 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1671 meanLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1672
1673 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1674 BOOST_CHECK(deserializedNetwork);
1675
1676 MeanLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1677 deserializedNetwork->Accept(verifier);
1678}
1679
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001680BOOST_AUTO_TEST_CASE(SerializeMerge)
1681{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001682 DECLARE_LAYER_VERIFIER_CLASS(Merge)
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001683
1684 const std::string layerName("merge");
1685 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1686
1687 armnn::INetworkPtr network = armnn::INetwork::Create();
1688 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1689 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1690 armnn::IConnectableLayer* const mergeLayer = network->AddMergeLayer(layerName.c_str());
1691 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1692
1693 inputLayer0->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(0));
1694 inputLayer1->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(1));
1695 mergeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1696
1697 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1698 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1699 mergeLayer->GetOutputSlot(0).SetTensorInfo(info);
1700
1701 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1702 BOOST_CHECK(deserializedNetwork);
1703
1704 MergeLayerVerifier verifier(layerName, {info, info}, {info});
1705 deserializedNetwork->Accept(verifier);
1706}
1707
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001708class MergerLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001709{
Jim Flynn5fa83932019-05-09 15:35:43 +01001710public:
1711 MergerLayerVerifier(const std::string& layerName,
1712 const std::vector<armnn::TensorInfo>& inputInfos,
1713 const std::vector<armnn::TensorInfo>& outputInfos,
1714 const armnn::OriginsDescriptor& descriptor)
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001715 : LayerVerifierBaseWithDescriptor<armnn::OriginsDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001716
Derek Lamberti859f9ce2019-12-10 22:05:21 +00001717 void VisitMergerLayer(const armnn::IConnectableLayer*,
1718 const armnn::OriginsDescriptor&,
1719 const char*) override
Jim Flynn5fa83932019-05-09 15:35:43 +01001720 {
Jim Flynne242f2d2019-05-22 14:24:13 +01001721 throw armnn::Exception("MergerLayer should have translated to ConcatLayer");
1722 }
1723
1724 void VisitConcatLayer(const armnn::IConnectableLayer* layer,
1725 const armnn::OriginsDescriptor& descriptor,
1726 const char* name) override
1727 {
Jim Flynn5fa83932019-05-09 15:35:43 +01001728 VerifyNameAndConnections(layer, name);
1729 VerifyDescriptor(descriptor);
1730 }
Jim Flynn5fa83932019-05-09 15:35:43 +01001731};
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001732
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001733// NOTE: Until the deprecated AddMergerLayer disappears this test checks that calling
Jim Flynne242f2d2019-05-22 14:24:13 +01001734// AddMergerLayer places a ConcatLayer into the serialized format and that
1735// when this deserialises we have a ConcatLayer
Jim Flynn5fa83932019-05-09 15:35:43 +01001736BOOST_AUTO_TEST_CASE(SerializeMerger)
1737{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001738 const std::string layerName("merger");
1739 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1740 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1741
1742 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1743
1744 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001745 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001746
1747 armnn::INetworkPtr network = armnn::INetwork::Create();
1748 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1749 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
Jim Flynn906f9462019-05-10 13:55:21 +01001750 ARMNN_NO_DEPRECATE_WARN_BEGIN
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001751 armnn::IConnectableLayer* const mergerLayer = network->AddMergerLayer(descriptor, layerName.c_str());
Jim Flynn906f9462019-05-10 13:55:21 +01001752 ARMNN_NO_DEPRECATE_WARN_END
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001753 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1754
1755 inputLayerOne->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0));
1756 inputLayerTwo->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1));
1757 mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1758
1759 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1760 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1761 mergerLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1762
Jim Flynn5fa83932019-05-09 15:35:43 +01001763 std::string mergerLayerNetwork = SerializeNetwork(*network);
1764 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(mergerLayerNetwork);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001765 BOOST_CHECK(deserializedNetwork);
1766
1767 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1768 deserializedNetwork->Accept(verifier);
1769}
1770
Jim Flynn5fa83932019-05-09 15:35:43 +01001771BOOST_AUTO_TEST_CASE(EnsureMergerLayerBackwardCompatibility)
1772{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001773 // The hex data below is a flat buffer containing a simple network with two inputs
Jim Flynne242f2d2019-05-22 14:24:13 +01001774 // a merger layer (now deprecated) and an output layer with dimensions as per the tensor infos below.
1775 //
1776 // This test verifies that we can still read back these old style
Jim Flynn5fa83932019-05-09 15:35:43 +01001777 // models replacing the MergerLayers with ConcatLayers with the same parameters.
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001778 const std::vector<uint8_t> mergerModel =
Jim Flynn5fa83932019-05-09 15:35:43 +01001779 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001780 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
1781 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1782 0x38, 0x02, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00,
1783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1784 0xF4, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x04, 0x00,
1785 0x00, 0x00, 0x9A, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
1786 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
1787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1788 0xF8, 0xFE, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
1789 0x00, 0x1F, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1790 0x68, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
1791 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1792 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
1793 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1794 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xFF, 0xFF, 0xFF,
1796 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1C, 0x00,
1797 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x72, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1798 0x5C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0xFF,
1799 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x92, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
1800 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00,
1801 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
1802 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
1803 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1804 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
1805 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00,
1806 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1807 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
1808 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
1809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1810 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
1811 0x00, 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1812 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
1813 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
1814 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00,
1815 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00,
1816 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
1817 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1818 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00,
1819 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00,
1820 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1821 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1822 0x02, 0x00, 0x00, 0x00
1823 };
1824
1825 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(mergerModel.begin(), mergerModel.end()));
Jim Flynn5fa83932019-05-09 15:35:43 +01001826 BOOST_CHECK(deserializedNetwork);
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001827
1828 const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 2, 3, 2, 2 }, armnn::DataType::Float32);
1829 const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 4, 3, 2, 2 }, armnn::DataType::Float32);
Jim Flynn5fa83932019-05-09 15:35:43 +01001830
1831 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1832
1833 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001834 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Jim Flynn5fa83932019-05-09 15:35:43 +01001835
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01001836 MergerLayerVerifier verifier("merger", { inputInfo, inputInfo }, { outputInfo }, descriptor);
Jim Flynn5fa83932019-05-09 15:35:43 +01001837 deserializedNetwork->Accept(verifier);
1838}
1839
Jim Flynne242f2d2019-05-22 14:24:13 +01001840BOOST_AUTO_TEST_CASE(SerializeConcat)
1841{
1842 const std::string layerName("concat");
1843 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1844 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1845
1846 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1847
1848 armnn::OriginsDescriptor descriptor =
1849 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1850
1851 armnn::INetworkPtr network = armnn::INetwork::Create();
1852 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1853 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1854 armnn::IConnectableLayer* const concatLayer = network->AddConcatLayer(descriptor, layerName.c_str());
1855 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1856
1857 inputLayerOne->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
1858 inputLayerTwo->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
1859 concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1860
1861 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1862 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1863 concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1864
1865 std::string concatLayerNetwork = SerializeNetwork(*network);
1866 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(concatLayerNetwork);
1867 BOOST_CHECK(deserializedNetwork);
1868
1869 // NOTE: using the MergerLayerVerifier to ensure that it is a concat layer and not a
1870 // merger layer that gets placed into the graph.
1871 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1872 deserializedNetwork->Accept(verifier);
1873}
1874
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001875BOOST_AUTO_TEST_CASE(SerializeMinimum)
1876{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001877 DECLARE_LAYER_VERIFIER_CLASS(Minimum)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001878
1879 const std::string layerName("minimum");
1880 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1881
1882 armnn::INetworkPtr network = armnn::INetwork::Create();
1883 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1884 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1885 armnn::IConnectableLayer* const minimumLayer = network->AddMinimumLayer(layerName.c_str());
1886 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1887
1888 inputLayer0->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(0));
1889 inputLayer1->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(1));
1890 minimumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1891
1892 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1893 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1894 minimumLayer->GetOutputSlot(0).SetTensorInfo(info);
1895
1896 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1897 BOOST_CHECK(deserializedNetwork);
1898
1899 MinimumLayerVerifier verifier(layerName, {info, info}, {info});
1900 deserializedNetwork->Accept(verifier);
1901}
1902
1903BOOST_AUTO_TEST_CASE(SerializeMultiplication)
1904{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001905 DECLARE_LAYER_VERIFIER_CLASS(Multiplication)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001906
1907 const std::string layerName("multiplication");
1908 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1909
1910 armnn::INetworkPtr network = armnn::INetwork::Create();
1911 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1912 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1913 armnn::IConnectableLayer* const multiplicationLayer = network->AddMultiplicationLayer(layerName.c_str());
1914 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1915
1916 inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(0));
1917 inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(1));
1918 multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1919
1920 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1921 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1922 multiplicationLayer->GetOutputSlot(0).SetTensorInfo(info);
1923
1924 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1925 BOOST_CHECK(deserializedNetwork);
1926
1927 MultiplicationLayerVerifier verifier(layerName, {info, info}, {info});
1928 deserializedNetwork->Accept(verifier);
1929}
1930
Ellen Norris-Thompson51982472019-06-19 11:46:21 +01001931BOOST_AUTO_TEST_CASE(SerializePrelu)
1932{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001933 DECLARE_LAYER_VERIFIER_CLASS(Prelu)
Ellen Norris-Thompson51982472019-06-19 11:46:21 +01001934
1935 const std::string layerName("prelu");
1936
1937 armnn::TensorInfo inputTensorInfo ({ 4, 1, 2 }, armnn::DataType::Float32);
1938 armnn::TensorInfo alphaTensorInfo ({ 5, 4, 3, 1 }, armnn::DataType::Float32);
1939 armnn::TensorInfo outputTensorInfo({ 5, 4, 3, 2 }, armnn::DataType::Float32);
1940
1941 armnn::INetworkPtr network = armnn::INetwork::Create();
1942 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1943 armnn::IConnectableLayer* const alphaLayer = network->AddInputLayer(1);
1944 armnn::IConnectableLayer* const preluLayer = network->AddPreluLayer(layerName.c_str());
1945 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1946
1947 inputLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(0));
1948 alphaLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(1));
1949 preluLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1950
1951 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
1952 alphaLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
1953 preluLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1954
1955 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1956 BOOST_CHECK(deserializedNetwork);
1957
1958 PreluLayerVerifier verifier(layerName, {inputTensorInfo, alphaTensorInfo}, {outputTensorInfo});
1959 deserializedNetwork->Accept(verifier);
1960}
1961
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001962BOOST_AUTO_TEST_CASE(SerializeNormalization)
1963{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001964 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Normalization)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001965
1966 const std::string layerName("normalization");
1967 const armnn::TensorInfo info({2, 1, 2, 2}, armnn::DataType::Float32);
1968
1969 armnn::NormalizationDescriptor desc;
1970 desc.m_DataLayout = armnn::DataLayout::NCHW;
1971 desc.m_NormSize = 3;
1972 desc.m_Alpha = 1;
1973 desc.m_Beta = 1;
1974 desc.m_K = 1;
1975
1976 armnn::INetworkPtr network = armnn::INetwork::Create();
1977 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1978 armnn::IConnectableLayer* const normalizationLayer = network->AddNormalizationLayer(desc, layerName.c_str());
1979 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1980
1981 inputLayer->GetOutputSlot(0).Connect(normalizationLayer->GetInputSlot(0));
1982 normalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1983
1984 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1985 normalizationLayer->GetOutputSlot(0).SetTensorInfo(info);
1986
1987 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1988 BOOST_CHECK(deserializedNetwork);
1989
1990 NormalizationLayerVerifier verifier(layerName, {info}, {info}, desc);
1991 deserializedNetwork->Accept(verifier);
1992}
1993
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01001994DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pad)
Jim Flynn965c7c62019-06-24 14:32:41 +01001995
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001996BOOST_AUTO_TEST_CASE(SerializePad)
1997{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001998 const std::string layerName("pad");
1999 const armnn::TensorInfo inputTensorInfo = armnn::TensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2000 const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({1, 3, 5, 7}, armnn::DataType::Float32);
2001
2002 armnn::PadDescriptor desc({{0, 0}, {1, 0}, {1, 1}, {1, 2}});
2003
2004 armnn::INetworkPtr network = armnn::INetwork::Create();
2005 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2006 armnn::IConnectableLayer* const padLayer = network->AddPadLayer(desc, layerName.c_str());
2007 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2008
2009 inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
2010 padLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2011
2012 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2013 padLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2014
2015 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2016 BOOST_CHECK(deserializedNetwork);
2017
2018 PadLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, desc);
2019 deserializedNetwork->Accept(verifier);
2020}
2021
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002022BOOST_AUTO_TEST_CASE(EnsurePadBackwardCompatibility)
Jim Flynn965c7c62019-06-24 14:32:41 +01002023{
2024 // The PadDescriptor is being extended with a float PadValue (so a value other than 0
2025 // can be used to pad the tensor.
2026 //
2027 // This test contains a binary representation of a simple input->pad->output network
2028 // prior to this change to test that the descriptor has been updated in a backward
2029 // compatible way with respect to Deserialization of older binary dumps
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002030 const std::vector<uint8_t> padModel =
Jim Flynn965c7c62019-06-24 14:32:41 +01002031 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002032 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2033 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2034 0x54, 0x01, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2035 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD0, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2036 0x04, 0x00, 0x00, 0x00, 0x96, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x9E, 0xFF, 0xFF, 0xFF, 0x04, 0x00,
2037 0x00, 0x00, 0x72, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2038 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
2039 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
2040 0x00, 0x00, 0x00, 0x00, 0x24, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x16, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00,
2041 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2042 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00,
2043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2044 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
2045 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00, 0x00, 0x00,
2046 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00,
2047 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
2048 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
2049 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2050 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2051 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
2052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00,
2053 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00,
2054 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2055 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00,
2056 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2057 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
2058 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2059 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
2060 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
2061 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00
2062 };
2063
2064 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(std::string(padModel.begin(), padModel.end()));
Jim Flynn965c7c62019-06-24 14:32:41 +01002065 BOOST_CHECK(deserializedNetwork);
2066
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002067 const armnn::TensorInfo inputInfo = armnn::TensorInfo({ 1, 2, 3, 4 }, armnn::DataType::Float32);
2068 const armnn::TensorInfo outputInfo = armnn::TensorInfo({ 1, 3, 5, 7 }, armnn::DataType::Float32);
Jim Flynn965c7c62019-06-24 14:32:41 +01002069
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002070 armnn::PadDescriptor descriptor({{ 0, 0 }, { 1, 0 }, { 1, 1 }, { 1, 2 }});
Jim Flynn965c7c62019-06-24 14:32:41 +01002071
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01002072 PadLayerVerifier verifier("pad", { inputInfo }, { outputInfo }, descriptor);
Jim Flynn965c7c62019-06-24 14:32:41 +01002073 deserializedNetwork->Accept(verifier);
2074}
2075
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002076BOOST_AUTO_TEST_CASE(SerializePermute)
2077{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002078 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Permute)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002079
2080 const std::string layerName("permute");
2081 const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2082 const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2083
2084 armnn::PermuteDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2085
2086 armnn::INetworkPtr network = armnn::INetwork::Create();
2087 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2088 armnn::IConnectableLayer* const permuteLayer = network->AddPermuteLayer(descriptor, layerName.c_str());
2089 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2090
2091 inputLayer->GetOutputSlot(0).Connect(permuteLayer->GetInputSlot(0));
2092 permuteLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2093
2094 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2095 permuteLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2096
2097 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2098 BOOST_CHECK(deserializedNetwork);
2099
2100 PermuteLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2101 deserializedNetwork->Accept(verifier);
2102}
2103
2104BOOST_AUTO_TEST_CASE(SerializePooling2d)
2105{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002106 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Pooling2d)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002107
2108 const std::string layerName("pooling2d");
2109 const armnn::TensorInfo inputInfo({1, 2, 2, 1}, armnn::DataType::Float32);
2110 const armnn::TensorInfo outputInfo({1, 1, 1, 1}, armnn::DataType::Float32);
2111
2112 armnn::Pooling2dDescriptor desc;
2113 desc.m_DataLayout = armnn::DataLayout::NHWC;
2114 desc.m_PadTop = 0;
2115 desc.m_PadBottom = 0;
2116 desc.m_PadLeft = 0;
2117 desc.m_PadRight = 0;
2118 desc.m_PoolType = armnn::PoolingAlgorithm::Average;
2119 desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
2120 desc.m_PaddingMethod = armnn::PaddingMethod::Exclude;
2121 desc.m_PoolHeight = 2;
2122 desc.m_PoolWidth = 2;
2123 desc.m_StrideX = 2;
2124 desc.m_StrideY = 2;
2125
2126 armnn::INetworkPtr network = armnn::INetwork::Create();
2127 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2128 armnn::IConnectableLayer* const pooling2dLayer = network->AddPooling2dLayer(desc, layerName.c_str());
2129 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2130
2131 inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0));
2132 pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2133
2134 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2135 pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2136
2137 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2138 BOOST_CHECK(deserializedNetwork);
2139
2140 Pooling2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2141 deserializedNetwork->Accept(verifier);
2142}
2143
Derek Lamberti87acb272019-03-27 16:51:31 +00002144BOOST_AUTO_TEST_CASE(SerializeQuantize)
2145{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002146 DECLARE_LAYER_VERIFIER_CLASS(Quantize)
Derek Lamberti87acb272019-03-27 16:51:31 +00002147
2148 const std::string layerName("quantize");
2149 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
2150
2151 armnn::INetworkPtr network = armnn::INetwork::Create();
2152 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2153 armnn::IConnectableLayer* const quantizeLayer = network->AddQuantizeLayer(layerName.c_str());
2154 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2155
2156 inputLayer->GetOutputSlot(0).Connect(quantizeLayer->GetInputSlot(0));
2157 quantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2158
2159 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2160 quantizeLayer->GetOutputSlot(0).SetTensorInfo(info);
2161
2162 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2163 BOOST_CHECK(deserializedNetwork);
2164
2165 QuantizeLayerVerifier verifier(layerName, {info}, {info});
2166 deserializedNetwork->Accept(verifier);
2167}
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002168
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002169BOOST_AUTO_TEST_CASE(SerializeReshape)
2170{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002171 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Reshape)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002172
2173 const std::string layerName("reshape");
2174 const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2175 const armnn::TensorInfo outputInfo({3, 3}, armnn::DataType::Float32);
2176
2177 armnn::ReshapeDescriptor descriptor({3, 3});
2178
2179 armnn::INetworkPtr network = armnn::INetwork::Create();
2180 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2181 armnn::IConnectableLayer* const reshapeLayer = network->AddReshapeLayer(descriptor, layerName.c_str());
2182 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2183
2184 inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0));
2185 reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2186
2187 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2188 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2189
2190 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2191 BOOST_CHECK(deserializedNetwork);
2192
2193 ReshapeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2194 deserializedNetwork->Accept(verifier);
2195}
2196
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002197BOOST_AUTO_TEST_CASE(SerializeResize)
2198{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002199 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Resize)
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002200
2201 const std::string layerName("resize");
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002202 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002203 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2204
2205 armnn::ResizeDescriptor desc;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002206 desc.m_TargetWidth = 4;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002207 desc.m_TargetHeight = 2;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002208 desc.m_Method = armnn::ResizeMethod::NearestNeighbor;
David Monahan4a0c9b92020-05-30 09:48:39 +01002209 desc.m_AlignCorners = true;
2210 desc.m_HalfPixelCenters = true;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002211
2212 armnn::INetworkPtr network = armnn::INetwork::Create();
2213 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2214 armnn::IConnectableLayer* const resizeLayer = network->AddResizeLayer(desc, layerName.c_str());
2215 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2216
2217 inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2218 resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2219
2220 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2221 resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2222
2223 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2224 BOOST_CHECK(deserializedNetwork);
2225
2226 ResizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2227 deserializedNetwork->Accept(verifier);
2228}
2229
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002230class ResizeBilinearLayerVerifier : public LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>
2231{
2232public:
2233 ResizeBilinearLayerVerifier(const std::string& layerName,
2234 const std::vector<armnn::TensorInfo>& inputInfos,
2235 const std::vector<armnn::TensorInfo>& outputInfos,
2236 const armnn::ResizeBilinearDescriptor& descriptor)
2237 : LayerVerifierBaseWithDescriptor<armnn::ResizeBilinearDescriptor>(
2238 layerName, inputInfos, outputInfos, descriptor) {}
2239
2240 void VisitResizeLayer(const armnn::IConnectableLayer* layer,
2241 const armnn::ResizeDescriptor& descriptor,
2242 const char* name) override
2243 {
2244 VerifyNameAndConnections(layer, name);
2245
David Monahan4a0c9b92020-05-30 09:48:39 +01002246 BOOST_CHECK(descriptor.m_Method == armnn::ResizeMethod::Bilinear);
2247 BOOST_CHECK(descriptor.m_TargetWidth == m_Descriptor.m_TargetWidth);
2248 BOOST_CHECK(descriptor.m_TargetHeight == m_Descriptor.m_TargetHeight);
2249 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
2250 BOOST_CHECK(descriptor.m_AlignCorners == m_Descriptor.m_AlignCorners);
2251 BOOST_CHECK(descriptor.m_HalfPixelCenters == m_Descriptor.m_HalfPixelCenters);
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002252 }
2253
2254 void VisitResizeBilinearLayer(const armnn::IConnectableLayer*,
2255 const armnn::ResizeBilinearDescriptor&,
2256 const char*) override
2257 {
2258 throw armnn::Exception("ResizeBilinearLayer should have translated to ResizeLayer");
2259 }
2260};
2261
2262// NOTE: Until the deprecated AddResizeBilinearLayer disappears this test checks that
2263// calling AddResizeBilinearLayer places a ResizeLayer into the serialized format
2264// and that when this deserialises we have a ResizeLayer
2265BOOST_AUTO_TEST_CASE(SerializeResizeBilinear)
2266{
2267 const std::string layerName("resizeBilinear");
2268 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2269 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2270
2271 armnn::ResizeBilinearDescriptor desc;
2272 desc.m_TargetWidth = 4u;
2273 desc.m_TargetHeight = 2u;
David Monahan4a0c9b92020-05-30 09:48:39 +01002274 desc.m_AlignCorners = true;
2275 desc.m_HalfPixelCenters = true;
Aron Virginas-Tarfe414cf2019-10-31 14:35:58 +00002276
2277 armnn::INetworkPtr network = armnn::INetwork::Create();
2278 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2279 ARMNN_NO_DEPRECATE_WARN_BEGIN
2280 armnn::IConnectableLayer* const resizeLayer = network->AddResizeBilinearLayer(desc, layerName.c_str());
2281 ARMNN_NO_DEPRECATE_WARN_END
2282 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2283
2284 inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2285 resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2286
2287 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2288 resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2289
2290 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2291 BOOST_CHECK(deserializedNetwork);
2292
2293 ResizeBilinearLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2294 deserializedNetwork->Accept(verifier);
2295}
2296
2297BOOST_AUTO_TEST_CASE(EnsureResizeBilinearBackwardCompatibility)
2298{
2299 // The hex data below is a flat buffer containing a simple network with an input,
2300 // a ResizeBilinearLayer (now deprecated) and an output
2301 //
2302 // This test verifies that we can still deserialize this old-style model by replacing
2303 // the ResizeBilinearLayer with an equivalent ResizeLayer
2304 const std::vector<uint8_t> resizeBilinearModel =
2305 {
2306 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
2307 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
2308 0x50, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2309 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD4, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
2310 0x04, 0x00, 0x00, 0x00, 0xC2, 0xFE, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
2311 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8A, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
2312 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
2313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2314 0x38, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
2315 0x00, 0x1A, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
2316 0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x08, 0x00, 0x0C, 0x00,
2317 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
2318 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0E, 0x00,
2319 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
2320 0x20, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x42, 0x69, 0x6C, 0x69,
2321 0x6E, 0x65, 0x61, 0x72, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2322 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
2323 0x00, 0x00, 0x52, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2324 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
2325 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2326 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
2327 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
2328 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00,
2329 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
2330 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00,
2332 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00,
2333 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2334 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
2335 0x00, 0x00, 0x05, 0x00, 0x00, 0x00
2336 };
2337
2338 armnn::INetworkPtr deserializedNetwork =
2339 DeserializeNetwork(std::string(resizeBilinearModel.begin(), resizeBilinearModel.end()));
2340 BOOST_CHECK(deserializedNetwork);
2341
2342 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2343 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2344
2345 armnn::ResizeBilinearDescriptor descriptor;
2346 descriptor.m_TargetWidth = 4u;
2347 descriptor.m_TargetHeight = 2u;
2348
2349 ResizeBilinearLayerVerifier verifier("resizeBilinear", { inputInfo }, { outputInfo }, descriptor);
2350 deserializedNetwork->Accept(verifier);
2351}
2352
Aron Virginas-Tar2fda80b2019-09-18 13:36:52 +01002353BOOST_AUTO_TEST_CASE(SerializeSlice)
2354{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002355 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Slice)
Aron Virginas-Tar2fda80b2019-09-18 13:36:52 +01002356
2357 const std::string layerName{"slice"};
2358
2359 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2360 const armnn::TensorInfo outputInfo = armnn::TensorInfo({2, 2, 2, 1}, armnn::DataType::Float32);
2361
2362 armnn::SliceDescriptor descriptor({ 0, 0, 1, 0}, {2, 2, 2, 1});
2363
2364 armnn::INetworkPtr network = armnn::INetwork::Create();
2365
2366 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2367 armnn::IConnectableLayer* const sliceLayer = network->AddSliceLayer(descriptor, layerName.c_str());
2368 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2369
2370 inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
2371 sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2372
2373 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2374 sliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2375
2376 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2377 BOOST_CHECK(deserializedNetwork);
2378
2379 SliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2380 deserializedNetwork->Accept(verifier);
2381}
2382
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002383BOOST_AUTO_TEST_CASE(SerializeSoftmax)
2384{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002385 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Softmax)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002386
2387 const std::string layerName("softmax");
2388 const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
2389
2390 armnn::SoftmaxDescriptor descriptor;
2391 descriptor.m_Beta = 1.0f;
2392
2393 armnn::INetworkPtr network = armnn::INetwork::Create();
2394 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2395 armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, layerName.c_str());
2396 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2397
2398 inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
2399 softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2400
2401 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2402 softmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
2403
2404 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2405 BOOST_CHECK(deserializedNetwork);
2406
2407 SoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
2408 deserializedNetwork->Accept(verifier);
2409}
2410
2411BOOST_AUTO_TEST_CASE(SerializeSpaceToBatchNd)
2412{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002413 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToBatchNd)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002414
2415 const std::string layerName("spaceToBatchNd");
2416 const armnn::TensorInfo inputInfo({2, 1, 2, 4}, armnn::DataType::Float32);
2417 const armnn::TensorInfo outputInfo({8, 1, 1, 3}, armnn::DataType::Float32);
2418
2419 armnn::SpaceToBatchNdDescriptor desc;
2420 desc.m_DataLayout = armnn::DataLayout::NCHW;
2421 desc.m_BlockShape = {2, 2};
2422 desc.m_PadList = {{0, 0}, {2, 0}};
2423
2424 armnn::INetworkPtr network = armnn::INetwork::Create();
2425 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2426 armnn::IConnectableLayer* const spaceToBatchNdLayer = network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2427 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2428
2429 inputLayer->GetOutputSlot(0).Connect(spaceToBatchNdLayer->GetInputSlot(0));
2430 spaceToBatchNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2431
2432 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2433 spaceToBatchNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2434
2435 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2436 BOOST_CHECK(deserializedNetwork);
2437
2438 SpaceToBatchNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2439 deserializedNetwork->Accept(verifier);
2440}
2441
Aron Virginas-Taraa067142019-06-11 16:01:44 +01002442BOOST_AUTO_TEST_CASE(SerializeSpaceToDepth)
2443{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002444 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(SpaceToDepth)
Aron Virginas-Taraa067142019-06-11 16:01:44 +01002445
2446 const std::string layerName("spaceToDepth");
2447
2448 const armnn::TensorInfo inputInfo ({ 1, 16, 8, 3 }, armnn::DataType::Float32);
2449 const armnn::TensorInfo outputInfo({ 1, 8, 4, 12 }, armnn::DataType::Float32);
2450
2451 armnn::SpaceToDepthDescriptor desc;
2452 desc.m_BlockSize = 2;
2453 desc.m_DataLayout = armnn::DataLayout::NHWC;
2454
2455 armnn::INetworkPtr network = armnn::INetwork::Create();
2456 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2457 armnn::IConnectableLayer* const spaceToDepthLayer = network->AddSpaceToDepthLayer(desc, layerName.c_str());
2458 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2459
2460 inputLayer->GetOutputSlot(0).Connect(spaceToDepthLayer->GetInputSlot(0));
2461 spaceToDepthLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2462
2463 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2464 spaceToDepthLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2465
2466 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2467 BOOST_CHECK(deserializedNetwork);
2468
2469 SpaceToDepthLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2470 deserializedNetwork->Accept(verifier);
2471}
2472
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002473BOOST_AUTO_TEST_CASE(SerializeSplitter)
2474{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002475 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Splitter)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002476
2477 const unsigned int numViews = 3;
2478 const unsigned int numDimensions = 4;
2479 const unsigned int inputShape[] = {1, 18, 4, 4};
2480 const unsigned int outputShape[] = {1, 6, 4, 4};
2481
2482 // This is modelled on how the caffe parser sets up a splitter layer to partition an input along dimension one.
2483 unsigned int splitterDimSizes[4] = {static_cast<unsigned int>(inputShape[0]),
2484 static_cast<unsigned int>(inputShape[1]),
2485 static_cast<unsigned int>(inputShape[2]),
2486 static_cast<unsigned int>(inputShape[3])};
2487 splitterDimSizes[1] /= numViews;
2488 armnn::ViewsDescriptor desc(numViews, numDimensions);
2489
2490 for (unsigned int g = 0; g < numViews; ++g)
2491 {
2492 desc.SetViewOriginCoord(g, 1, splitterDimSizes[1] * g);
2493
2494 for (unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
2495 {
2496 desc.SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
2497 }
2498 }
2499
2500 const std::string layerName("splitter");
2501 const armnn::TensorInfo inputInfo(numDimensions, inputShape, armnn::DataType::Float32);
2502 const armnn::TensorInfo outputInfo(numDimensions, outputShape, armnn::DataType::Float32);
2503
2504 armnn::INetworkPtr network = armnn::INetwork::Create();
2505 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2506 armnn::IConnectableLayer* const splitterLayer = network->AddSplitterLayer(desc, layerName.c_str());
2507 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2508 armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2509 armnn::IConnectableLayer* const outputLayer2 = network->AddOutputLayer(2);
2510
2511 inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
2512 splitterLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2513 splitterLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2514 splitterLayer->GetOutputSlot(2).Connect(outputLayer2->GetInputSlot(0));
2515
2516 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2517 splitterLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2518 splitterLayer->GetOutputSlot(1).SetTensorInfo(outputInfo);
2519 splitterLayer->GetOutputSlot(2).SetTensorInfo(outputInfo);
2520
2521 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2522 BOOST_CHECK(deserializedNetwork);
2523
2524 SplitterLayerVerifier verifier(layerName, {inputInfo}, {outputInfo, outputInfo, outputInfo}, desc);
2525 deserializedNetwork->Accept(verifier);
2526}
2527
Matthew Jacksonb5433ee2019-07-11 15:54:20 +01002528BOOST_AUTO_TEST_CASE(SerializeStack)
2529{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002530 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Stack)
Matthew Jacksonb5433ee2019-07-11 15:54:20 +01002531
2532 const std::string layerName("stack");
2533
2534 armnn::TensorInfo inputTensorInfo ({4, 3, 5}, armnn::DataType::Float32);
2535 armnn::TensorInfo outputTensorInfo({4, 3, 2, 5}, armnn::DataType::Float32);
2536
2537 armnn::StackDescriptor descriptor(2, 2, {4, 3, 5});
2538
2539 armnn::INetworkPtr network = armnn::INetwork::Create();
2540 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
2541 armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
2542 armnn::IConnectableLayer* const stackLayer = network->AddStackLayer(descriptor, layerName.c_str());
2543 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2544
2545 inputLayer1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
2546 inputLayer2->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
2547 stackLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2548
2549 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2550 inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2551 stackLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2552
2553 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2554 BOOST_CHECK(deserializedNetwork);
2555
2556 StackLayerVerifier verifier(layerName, {inputTensorInfo, inputTensorInfo}, {outputTensorInfo}, descriptor);
2557 deserializedNetwork->Accept(verifier);
2558}
2559
Aron Virginas-Tar85121a22019-10-23 10:41:35 +01002560BOOST_AUTO_TEST_CASE(SerializeStandIn)
2561{
2562 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StandIn)
2563
2564 const std::string layerName("standIn");
2565
2566 armnn::TensorInfo tensorInfo({ 1u }, armnn::DataType::Float32);
2567 armnn::StandInDescriptor descriptor(2u, 2u);
2568
2569 armnn::INetworkPtr network = armnn::INetwork::Create();
2570 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2571 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2572 armnn::IConnectableLayer* const standInLayer = network->AddStandInLayer(descriptor, layerName.c_str());
2573 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2574 armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2575
2576 inputLayer0->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(0));
2577 inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2578
2579 inputLayer1->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(1));
2580 inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2581
2582 standInLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2583 standInLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2584
2585 standInLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2586 standInLayer->GetOutputSlot(1).SetTensorInfo(tensorInfo);
2587
2588 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2589 BOOST_CHECK(deserializedNetwork);
2590
2591 StandInLayerVerifier verifier(layerName, { tensorInfo, tensorInfo }, { tensorInfo, tensorInfo }, descriptor);
2592 deserializedNetwork->Accept(verifier);
2593}
2594
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002595BOOST_AUTO_TEST_CASE(SerializeStridedSlice)
2596{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002597 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(StridedSlice)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002598
2599 const std::string layerName("stridedSlice");
2600 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2601 const armnn::TensorInfo outputInfo = armnn::TensorInfo({3, 1}, armnn::DataType::Float32);
2602
2603 armnn::StridedSliceDescriptor desc({0, 0, 1, 0}, {1, 1, 1, 1}, {1, 1, 1, 1});
2604 desc.m_EndMask = (1 << 4) - 1;
2605 desc.m_ShrinkAxisMask = (1 << 1) | (1 << 2);
2606 desc.m_DataLayout = armnn::DataLayout::NCHW;
2607
2608 armnn::INetworkPtr network = armnn::INetwork::Create();
2609 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2610 armnn::IConnectableLayer* const stridedSliceLayer = network->AddStridedSliceLayer(desc, layerName.c_str());
2611 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2612
2613 inputLayer->GetOutputSlot(0).Connect(stridedSliceLayer->GetInputSlot(0));
2614 stridedSliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2615
2616 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2617 stridedSliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2618
2619 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2620 BOOST_CHECK(deserializedNetwork);
2621
2622 StridedSliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2623 deserializedNetwork->Accept(verifier);
2624}
2625
2626BOOST_AUTO_TEST_CASE(SerializeSubtraction)
2627{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002628 DECLARE_LAYER_VERIFIER_CLASS(Subtraction)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002629
2630 const std::string layerName("subtraction");
2631 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2632
2633 armnn::INetworkPtr network = armnn::INetwork::Create();
2634 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2635 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2636 armnn::IConnectableLayer* const subtractionLayer = network->AddSubtractionLayer(layerName.c_str());
2637 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2638
2639 inputLayer0->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(0));
2640 inputLayer1->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(1));
2641 subtractionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2642
2643 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2644 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2645 subtractionLayer->GetOutputSlot(0).SetTensorInfo(info);
2646
2647 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2648 BOOST_CHECK(deserializedNetwork);
2649
2650 SubtractionLayerVerifier verifier(layerName, {info, info}, {info});
2651 deserializedNetwork->Accept(verifier);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00002652}
2653
Sadik Armaganeff363d2019-04-05 15:25:46 +01002654BOOST_AUTO_TEST_CASE(SerializeSwitch)
2655{
2656 class SwitchLayerVerifier : public LayerVerifierBase
2657 {
2658 public:
2659 SwitchLayerVerifier(const std::string& layerName,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002660 const std::vector<armnn::TensorInfo>& inputInfos,
2661 const std::vector<armnn::TensorInfo>& outputInfos)
Sadik Armaganeff363d2019-04-05 15:25:46 +01002662 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2663
2664 void VisitSwitchLayer(const armnn::IConnectableLayer* layer, const char* name) override
2665 {
2666 VerifyNameAndConnections(layer, name);
2667 }
2668
Derek Lamberti859f9ce2019-12-10 22:05:21 +00002669 void VisitConstantLayer(const armnn::IConnectableLayer*,
2670 const armnn::ConstTensor&,
2671 const char*) override {}
Sadik Armaganeff363d2019-04-05 15:25:46 +01002672 };
2673
2674 const std::string layerName("switch");
2675 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2676
2677 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2678 armnn::ConstTensor constTensor(info, constantData);
2679
2680 armnn::INetworkPtr network = armnn::INetwork::Create();
2681 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2682 armnn::IConnectableLayer* const constantLayer = network->AddConstantLayer(constTensor, "constant");
2683 armnn::IConnectableLayer* const switchLayer = network->AddSwitchLayer(layerName.c_str());
2684 armnn::IConnectableLayer* const trueOutputLayer = network->AddOutputLayer(0);
2685 armnn::IConnectableLayer* const falseOutputLayer = network->AddOutputLayer(1);
2686
2687 inputLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(0));
2688 constantLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(1));
2689 switchLayer->GetOutputSlot(0).Connect(trueOutputLayer->GetInputSlot(0));
2690 switchLayer->GetOutputSlot(1).Connect(falseOutputLayer->GetInputSlot(0));
2691
2692 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2693 constantLayer->GetOutputSlot(0).SetTensorInfo(info);
2694 switchLayer->GetOutputSlot(0).SetTensorInfo(info);
2695 switchLayer->GetOutputSlot(1).SetTensorInfo(info);
2696
2697 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2698 BOOST_CHECK(deserializedNetwork);
2699
2700 SwitchLayerVerifier verifier(layerName, {info, info}, {info, info});
2701 deserializedNetwork->Accept(verifier);
2702}
2703
Mike Kellyc9ea45a2020-02-28 18:11:58 +00002704BOOST_AUTO_TEST_CASE(SerializeTranspose)
2705{
2706 DECLARE_LAYER_VERIFIER_CLASS_WITH_DESCRIPTOR(Transpose)
2707
2708 const std::string layerName("transpose");
2709 const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2710 const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2711
2712 armnn::TransposeDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2713
2714 armnn::INetworkPtr network = armnn::INetwork::Create();
2715 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2716 armnn::IConnectableLayer* const transposeLayer = network->AddTransposeLayer(descriptor, layerName.c_str());
2717 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2718
2719 inputLayer->GetOutputSlot(0).Connect(transposeLayer->GetInputSlot(0));
2720 transposeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2721
2722 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2723 transposeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2724
2725 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2726 BOOST_CHECK(deserializedNetwork);
2727
2728 TransposeLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2729 deserializedNetwork->Accept(verifier);
2730}
2731
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002732BOOST_AUTO_TEST_CASE(SerializeTransposeConvolution2d)
2733{
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002734 using Descriptor = armnn::TransposeConvolution2dDescriptor;
2735 class TransposeConvolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Descriptor>
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002736 {
2737 public:
2738 TransposeConvolution2dLayerVerifier(const std::string& layerName,
2739 const std::vector<armnn::TensorInfo>& inputInfos,
2740 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002741 const Descriptor& descriptor,
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002742 const armnn::ConstTensor& weights,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002743 const armnn::Optional<armnn::ConstTensor>& biases)
2744 : LayerVerifierBaseWithDescriptor<Descriptor>(layerName, inputInfos, outputInfos, descriptor)
2745 , m_Weights(weights)
2746 , m_Biases(biases)
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002747 {}
2748
2749 void VisitTransposeConvolution2dLayer(const armnn::IConnectableLayer* layer,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002750 const Descriptor& descriptor,
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002751 const armnn::ConstTensor& weights,
2752 const armnn::Optional<armnn::ConstTensor>& biases,
2753 const char* name) override
2754 {
2755 VerifyNameAndConnections(layer, name);
2756 VerifyDescriptor(descriptor);
2757
2758 // check weights
2759 CompareConstTensor(weights, m_Weights);
2760
2761 // check biases
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002762 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002763 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
2764
2765 if (biases.has_value() && m_Biases.has_value())
2766 {
2767 CompareConstTensor(biases.value(), m_Biases.value());
2768 }
2769 }
2770
2771 private:
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002772 armnn::ConstTensor m_Weights;
2773 armnn::Optional<armnn::ConstTensor> m_Biases;
2774 };
2775
2776 const std::string layerName("transposeConvolution2d");
2777 const armnn::TensorInfo inputInfo ({ 1, 7, 7, 1 }, armnn::DataType::Float32);
2778 const armnn::TensorInfo outputInfo({ 1, 9, 9, 1 }, armnn::DataType::Float32);
2779
2780 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
2781 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
2782
2783 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
2784 armnn::ConstTensor weights(weightsInfo, weightsData);
2785
2786 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
2787 armnn::ConstTensor biases(biasesInfo, biasesData);
2788
2789 armnn::TransposeConvolution2dDescriptor descriptor;
2790 descriptor.m_PadLeft = 1;
2791 descriptor.m_PadRight = 1;
2792 descriptor.m_PadTop = 1;
2793 descriptor.m_PadBottom = 1;
2794 descriptor.m_StrideX = 1;
2795 descriptor.m_StrideY = 1;
2796 descriptor.m_BiasEnabled = true;
2797 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
2798
2799 armnn::INetworkPtr network = armnn::INetwork::Create();
2800 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2801 armnn::IConnectableLayer* const convLayer =
2802 network->AddTransposeConvolution2dLayer(descriptor,
2803 weights,
2804 armnn::Optional<armnn::ConstTensor>(biases),
2805 layerName.c_str());
2806 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2807
2808 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
2809 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2810
2811 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2812 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2813
2814 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2815 BOOST_CHECK(deserializedNetwork);
2816
2817 TransposeConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
2818 deserializedNetwork->Accept(verifier);
2819}
2820
Sadik Armagandb059fd2019-03-20 12:28:32 +00002821BOOST_AUTO_TEST_CASE(SerializeDeserializeNonLinearNetwork)
2822{
2823 class ConstantLayerVerifier : public LayerVerifierBase
2824 {
2825 public:
2826 ConstantLayerVerifier(const std::string& layerName,
2827 const std::vector<armnn::TensorInfo>& inputInfos,
2828 const std::vector<armnn::TensorInfo>& outputInfos,
2829 const armnn::ConstTensor& layerInput)
2830 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2831 , m_LayerInput(layerInput) {}
2832
2833 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
2834 const armnn::ConstTensor& input,
2835 const char* name) override
2836 {
2837 VerifyNameAndConnections(layer, name);
Sadik Armagandb059fd2019-03-20 12:28:32 +00002838 CompareConstTensor(input, m_LayerInput);
2839 }
2840
Derek Lamberti859f9ce2019-12-10 22:05:21 +00002841 void VisitAdditionLayer(const armnn::IConnectableLayer*, const char*) override {}
Sadik Armagandb059fd2019-03-20 12:28:32 +00002842
2843 private:
2844 armnn::ConstTensor m_LayerInput;
2845 };
2846
2847 const std::string layerName("constant");
2848 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
2849
2850 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2851 armnn::ConstTensor constTensor(info, constantData);
2852
2853 armnn::INetworkPtr network(armnn::INetwork::Create());
2854 armnn::IConnectableLayer* input = network->AddInputLayer(0);
2855 armnn::IConnectableLayer* add = network->AddAdditionLayer();
2856 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
2857 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
2858
2859 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
2860 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
2861 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2862
2863 input->GetOutputSlot(0).SetTensorInfo(info);
2864 constant->GetOutputSlot(0).SetTensorInfo(info);
2865 add->GetOutputSlot(0).SetTensorInfo(info);
2866
2867 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2868 BOOST_CHECK(deserializedNetwork);
2869
2870 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
2871 deserializedNetwork->Accept(verifier);
2872}
2873
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002874class VerifyLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>
Jim Flynn11af3752019-03-19 17:22:29 +00002875{
2876public:
2877 VerifyLstmLayer(const std::string& layerName,
2878 const std::vector<armnn::TensorInfo>& inputInfos,
2879 const std::vector<armnn::TensorInfo>& outputInfos,
2880 const armnn::LstmDescriptor& descriptor,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002881 const armnn::LstmInputParams& inputParams)
2882 : LayerVerifierBaseWithDescriptor<armnn::LstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
2883 , m_InputParams(inputParams) {}
2884
Jim Flynn11af3752019-03-19 17:22:29 +00002885 void VisitLstmLayer(const armnn::IConnectableLayer* layer,
2886 const armnn::LstmDescriptor& descriptor,
2887 const armnn::LstmInputParams& params,
2888 const char* name)
2889 {
2890 VerifyNameAndConnections(layer, name);
2891 VerifyDescriptor(descriptor);
2892 VerifyInputParameters(params);
2893 }
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002894
Jim Flynn11af3752019-03-19 17:22:29 +00002895protected:
Jim Flynn11af3752019-03-19 17:22:29 +00002896 void VerifyInputParameters(const armnn::LstmInputParams& params)
2897 {
2898 VerifyConstTensors(
2899 "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
2900 VerifyConstTensors(
2901 "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
2902 VerifyConstTensors(
2903 "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
2904 VerifyConstTensors(
2905 "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
2906 VerifyConstTensors(
2907 "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
2908 VerifyConstTensors(
2909 "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
2910 VerifyConstTensors(
2911 "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
2912 VerifyConstTensors(
2913 "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
2914 VerifyConstTensors(
2915 "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
2916 VerifyConstTensors(
2917 "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
2918 VerifyConstTensors(
2919 "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
2920 VerifyConstTensors(
2921 "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
2922 VerifyConstTensors(
2923 "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
2924 VerifyConstTensors(
2925 "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
2926 VerifyConstTensors(
2927 "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
2928 VerifyConstTensors(
2929 "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
2930 VerifyConstTensors(
2931 "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
Jan Eilersf8c62972019-07-17 11:07:49 +01002932 VerifyConstTensors(
2933 "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
2934 VerifyConstTensors(
2935 "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
2936 VerifyConstTensors(
2937 "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
2938 VerifyConstTensors(
2939 "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
Jim Flynn11af3752019-03-19 17:22:29 +00002940 }
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01002941
Jim Flynn11af3752019-03-19 17:22:29 +00002942private:
Jim Flynn11af3752019-03-19 17:22:29 +00002943 armnn::LstmInputParams m_InputParams;
2944};
2945
2946BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmCifgPeepholeNoProjection)
2947{
2948 armnn::LstmDescriptor descriptor;
2949 descriptor.m_ActivationFunc = 4;
2950 descriptor.m_ClippingThresProj = 0.0f;
2951 descriptor.m_ClippingThresCell = 0.0f;
2952 descriptor.m_CifgEnabled = true; // if this is true then we DON'T need to set the OptCifgParams
2953 descriptor.m_ProjectionEnabled = false;
2954 descriptor.m_PeepholeEnabled = true;
2955
2956 const uint32_t batchSize = 1;
2957 const uint32_t inputSize = 2;
2958 const uint32_t numUnits = 4;
2959 const uint32_t outputSize = numUnits;
2960
2961 armnn::TensorInfo inputWeightsInfo1({numUnits, inputSize}, armnn::DataType::Float32);
2962 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
2963 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo1, inputToForgetWeightsData);
2964
2965 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
2966 armnn::ConstTensor inputToCellWeights(inputWeightsInfo1, inputToCellWeightsData);
2967
2968 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
2969 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo1, inputToOutputWeightsData);
2970
2971 armnn::TensorInfo inputWeightsInfo2({numUnits, outputSize}, armnn::DataType::Float32);
2972 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
2973 armnn::ConstTensor recurrentToForgetWeights(inputWeightsInfo2, recurrentToForgetWeightsData);
2974
2975 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
2976 armnn::ConstTensor recurrentToCellWeights(inputWeightsInfo2, recurrentToCellWeightsData);
2977
2978 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
2979 armnn::ConstTensor recurrentToOutputWeights(inputWeightsInfo2, recurrentToOutputWeightsData);
2980
2981 armnn::TensorInfo inputWeightsInfo3({numUnits}, armnn::DataType::Float32);
2982 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
2983 armnn::ConstTensor cellToForgetWeights(inputWeightsInfo3, cellToForgetWeightsData);
2984
2985 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
2986 armnn::ConstTensor cellToOutputWeights(inputWeightsInfo3, cellToOutputWeightsData);
2987
2988 std::vector<float> forgetGateBiasData(numUnits, 1.0f);
2989 armnn::ConstTensor forgetGateBias(inputWeightsInfo3, forgetGateBiasData);
2990
2991 std::vector<float> cellBiasData(numUnits, 0.0f);
2992 armnn::ConstTensor cellBias(inputWeightsInfo3, cellBiasData);
2993
2994 std::vector<float> outputGateBiasData(numUnits, 0.0f);
2995 armnn::ConstTensor outputGateBias(inputWeightsInfo3, outputGateBiasData);
2996
2997 armnn::LstmInputParams params;
2998 params.m_InputToForgetWeights = &inputToForgetWeights;
2999 params.m_InputToCellWeights = &inputToCellWeights;
3000 params.m_InputToOutputWeights = &inputToOutputWeights;
3001 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3002 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3003 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3004 params.m_ForgetGateBias = &forgetGateBias;
3005 params.m_CellBias = &cellBias;
3006 params.m_OutputGateBias = &outputGateBias;
3007 params.m_CellToForgetWeights = &cellToForgetWeights;
3008 params.m_CellToOutputWeights = &cellToOutputWeights;
3009
3010 armnn::INetworkPtr network = armnn::INetwork::Create();
3011 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3012 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3013 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3014 const std::string layerName("lstm");
3015 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3016 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3017 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3018 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3019 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3020
3021 // connect up
3022 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3023 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3024 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3025 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 3 }, armnn::DataType::Float32);
3026
3027 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3028 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3029
3030 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3031 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3032
3033 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3034 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3035
3036 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3037 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3038
3039 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3040 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3041
3042 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3043 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3044
3045 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3046 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3047
3048 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3049 BOOST_CHECK(deserializedNetwork);
3050
3051 VerifyLstmLayer checker(
3052 layerName,
3053 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3054 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3055 descriptor,
3056 params);
3057 deserializedNetwork->Accept(checker);
3058}
3059
3060BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeAndProjection)
3061{
3062 armnn::LstmDescriptor descriptor;
3063 descriptor.m_ActivationFunc = 4;
3064 descriptor.m_ClippingThresProj = 0.0f;
3065 descriptor.m_ClippingThresCell = 0.0f;
3066 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3067 descriptor.m_ProjectionEnabled = true;
3068 descriptor.m_PeepholeEnabled = true;
3069
3070 const uint32_t batchSize = 2;
3071 const uint32_t inputSize = 5;
3072 const uint32_t numUnits = 20;
3073 const uint32_t outputSize = 16;
3074
3075 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3076 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3077 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3078
3079 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3080 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3081
3082 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3083 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3084
3085 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3086 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3087
3088 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3089 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3090 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3091
3092 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3093 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3094
3095 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3096 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3097
3098 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3099 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3100
3101 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3102 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3103 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3104
3105 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3106 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3107
3108 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3109 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3110
3111 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3112 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3113
3114 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3115 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3116
3117 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3118 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3119
3120 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3121 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3122
3123 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3124 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3125 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3126
3127 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3128 std::vector<float> projectionBiasData(outputSize, 0.f);
3129 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3130
3131 armnn::LstmInputParams params;
3132 params.m_InputToForgetWeights = &inputToForgetWeights;
3133 params.m_InputToCellWeights = &inputToCellWeights;
3134 params.m_InputToOutputWeights = &inputToOutputWeights;
3135 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3136 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3137 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3138 params.m_ForgetGateBias = &forgetGateBias;
3139 params.m_CellBias = &cellBias;
3140 params.m_OutputGateBias = &outputGateBias;
3141
3142 // additional params because: descriptor.m_CifgEnabled = false
3143 params.m_InputToInputWeights = &inputToInputWeights;
3144 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3145 params.m_CellToInputWeights = &cellToInputWeights;
3146 params.m_InputGateBias = &inputGateBias;
3147
3148 // additional params because: descriptor.m_ProjectionEnabled = true
3149 params.m_ProjectionWeights = &projectionWeights;
3150 params.m_ProjectionBias = &projectionBias;
3151
3152 // additional params because: descriptor.m_PeepholeEnabled = true
3153 params.m_CellToForgetWeights = &cellToForgetWeights;
3154 params.m_CellToOutputWeights = &cellToOutputWeights;
3155
3156 armnn::INetworkPtr network = armnn::INetwork::Create();
3157 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3158 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3159 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3160 const std::string layerName("lstm");
3161 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3162 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3163 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3164 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3165 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3166
3167 // connect up
3168 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3169 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3170 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3171 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3172
3173 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3174 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3175
3176 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3177 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3178
3179 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3180 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3181
3182 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3183 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3184
3185 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3186 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3187
3188 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3189 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3190
3191 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3192 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3193
3194 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3195 BOOST_CHECK(deserializedNetwork);
3196
3197 VerifyLstmLayer checker(
3198 layerName,
3199 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3200 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3201 descriptor,
3202 params);
3203 deserializedNetwork->Accept(checker);
3204}
3205
Jan Eilersf8c62972019-07-17 11:07:49 +01003206BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeWithProjectionWithLayerNorm)
3207{
3208 armnn::LstmDescriptor descriptor;
3209 descriptor.m_ActivationFunc = 4;
3210 descriptor.m_ClippingThresProj = 0.0f;
3211 descriptor.m_ClippingThresCell = 0.0f;
3212 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3213 descriptor.m_ProjectionEnabled = true;
3214 descriptor.m_PeepholeEnabled = true;
3215 descriptor.m_LayerNormEnabled = true;
3216
3217 const uint32_t batchSize = 2;
3218 const uint32_t inputSize = 5;
3219 const uint32_t numUnits = 20;
3220 const uint32_t outputSize = 16;
3221
3222 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3223 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3224 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3225
3226 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3227 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3228
3229 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3230 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3231
3232 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3233 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3234
3235 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3236 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3237 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3238
3239 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3240 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3241
3242 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3243 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3244
3245 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3246 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3247
3248 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3249 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3250 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3251
3252 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3253 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3254
3255 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3256 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3257
3258 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3259 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3260
3261 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3262 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3263
3264 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3265 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3266
3267 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3268 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3269
3270 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3271 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3272 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3273
3274 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3275 std::vector<float> projectionBiasData(outputSize, 0.f);
3276 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3277
3278 std::vector<float> inputLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3279 armnn::ConstTensor inputLayerNormWeights(tensorInfo20, forgetGateBiasData);
3280
3281 std::vector<float> forgetLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3282 armnn::ConstTensor forgetLayerNormWeights(tensorInfo20, forgetGateBiasData);
3283
3284 std::vector<float> cellLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3285 armnn::ConstTensor cellLayerNormWeights(tensorInfo20, forgetGateBiasData);
3286
3287 std::vector<float> outLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3288 armnn::ConstTensor outLayerNormWeights(tensorInfo20, forgetGateBiasData);
3289
3290 armnn::LstmInputParams params;
3291 params.m_InputToForgetWeights = &inputToForgetWeights;
3292 params.m_InputToCellWeights = &inputToCellWeights;
3293 params.m_InputToOutputWeights = &inputToOutputWeights;
3294 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3295 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3296 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3297 params.m_ForgetGateBias = &forgetGateBias;
3298 params.m_CellBias = &cellBias;
3299 params.m_OutputGateBias = &outputGateBias;
3300
3301 // additional params because: descriptor.m_CifgEnabled = false
3302 params.m_InputToInputWeights = &inputToInputWeights;
3303 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3304 params.m_CellToInputWeights = &cellToInputWeights;
3305 params.m_InputGateBias = &inputGateBias;
3306
3307 // additional params because: descriptor.m_ProjectionEnabled = true
3308 params.m_ProjectionWeights = &projectionWeights;
3309 params.m_ProjectionBias = &projectionBias;
3310
3311 // additional params because: descriptor.m_PeepholeEnabled = true
3312 params.m_CellToForgetWeights = &cellToForgetWeights;
3313 params.m_CellToOutputWeights = &cellToOutputWeights;
3314
3315 // additional params because: despriptor.m_LayerNormEnabled = true
3316 params.m_InputLayerNormWeights = &inputLayerNormWeights;
3317 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3318 params.m_CellLayerNormWeights = &cellLayerNormWeights;
3319 params.m_OutputLayerNormWeights = &outLayerNormWeights;
3320
3321 armnn::INetworkPtr network = armnn::INetwork::Create();
3322 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3323 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3324 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3325 const std::string layerName("lstm");
3326 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3327 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3328 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3329 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3330 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3331
3332 // connect up
3333 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3334 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3335 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3336 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3337
3338 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3339 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3340
3341 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3342 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3343
3344 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3345 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3346
3347 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3348 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3349
3350 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3351 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3352
3353 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3354 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3355
3356 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3357 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3358
3359 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3360 BOOST_CHECK(deserializedNetwork);
3361
3362 VerifyLstmLayer checker(
3363 layerName,
3364 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3365 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3366 descriptor,
3367 params);
3368 deserializedNetwork->Accept(checker);
3369}
3370
3371BOOST_AUTO_TEST_CASE(EnsureLstmLayersBackwardCompatibility)
3372{
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003373 // The hex data below is a flat buffer containing a lstm layer with no Cifg, with peephole and projection
3374 // enabled. That data was obtained before additional layer normalization parameters where added to the
3375 // lstm serializer. That way it can be tested if a lstm model with the old parameter configuration can
3376 // still be loaded
3377 const std::vector<uint8_t> lstmNoCifgWithPeepholeAndProjectionModel =
Jan Eilersf8c62972019-07-17 11:07:49 +01003378 {
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003379 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00,
3380 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
3381 0xDC, 0x29, 0x00, 0x00, 0x38, 0x29, 0x00, 0x00, 0xB4, 0x28, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x3C, 0x01,
3382 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
3383 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
3384 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0xD6, 0xFF, 0xFF,
3385 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x06, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x88, 0xD7,
3386 0xFF, 0xFF, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF6, 0xD6, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
3387 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
3388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3389 0xE8, 0xD7, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xFF, 0xFF, 0x00, 0x00,
3390 0x00, 0x0B, 0x04, 0x00, 0x00, 0x00, 0x5E, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xE0, 0xD7, 0xFF, 0xFF,
3391 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4E, 0xD7, 0xFF, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00,
3392 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3393 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD8,
3394 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B,
3395 0x04, 0x00, 0x00, 0x00, 0xB6, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x38, 0xD8, 0xFF, 0xFF, 0x08, 0x00,
3396 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA6, 0xD7, 0xFF, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3397 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3398 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xD8, 0xFF, 0xFF,
3399 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0B, 0x04, 0x00,
3400 0x00, 0x00, 0x0E, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x16, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3401 0xFA, 0xD7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00,
3402 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3403 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD8, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
3404 0x00, 0x00, 0x6C, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
3405 0x12, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE0, 0x25, 0x00, 0x00, 0xD0, 0x25,
3406 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x48, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00,
3407 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2C, 0x00, 0x30, 0x00,
3408 0x34, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x40, 0x00, 0x44, 0x00, 0x26, 0x00, 0x00, 0x00, 0xC4, 0x23, 0x00, 0x00,
3409 0xF8, 0x21, 0x00, 0x00, 0x2C, 0x20, 0x00, 0x00, 0xF0, 0x1A, 0x00, 0x00, 0xB4, 0x15, 0x00, 0x00, 0x78, 0x10,
3410 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x68, 0x0F, 0x00, 0x00, 0xE0, 0x0E, 0x00, 0x00, 0x14, 0x0D, 0x00, 0x00,
3411 0xD8, 0x07, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0xC8, 0x06, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x14, 0x01,
3412 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xD7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3413 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFE, 0xD8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00,
3414 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3416 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3418 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3419 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x72, 0xD8,
3420 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0xD9, 0xFF, 0xFF,
3421 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3422 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3424 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3425 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xD8,
3426 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3427 0x14, 0x00, 0x00, 0x00, 0xF6, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x54, 0x00, 0x00, 0x00, 0x04, 0x00,
3428 0x00, 0x00, 0x06, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3431 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3432 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xD9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3433 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6A, 0xD9, 0xFF, 0xFF, 0x00, 0x00,
3434 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7A, 0xDA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00,
3435 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3436 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3437 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3438 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3439 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3440 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3441 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3442 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3444 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3445 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3446 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3447 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3448 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3449 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3451 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3457 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3469 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3473 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3478 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3481 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3482 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3492 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3493 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3494 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3495 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3500 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xDE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3507 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xA2, 0xDE,
3508 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB2, 0xDF, 0xFF, 0xFF,
3509 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xDF,
3514 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
3515 0x14, 0x00, 0x00, 0x00, 0x26, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00,
3516 0x00, 0x00, 0x36, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3517 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3520 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3521 0x00, 0x00, 0x00, 0x00, 0x92, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3522 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAA, 0xDF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3523 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xBA, 0xE0, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3524 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3525 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3526 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3527 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3530 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3531 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3532 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3533 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3534 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3535 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3536 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3537 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3541 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3542 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3543 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3581 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3589 0x00, 0x00, 0x00, 0x00, 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, 0xC6, 0xE4, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3596 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xE2, 0xE4, 0xFF, 0xFF,
3597 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xE5, 0xFF, 0xFF, 0x04, 0x00,
3598 0x00, 0x00, 0x64, 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, 0x8E, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3621 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
3622 0x00, 0x00, 0xAA, 0xE6, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3623 0xBA, 0xE7, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 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, 0x16, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3629 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2E, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x64, 0x00,
3630 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3E, 0xE8, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x14, 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, 0x9A, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xB2, 0xE7, 0xFF, 0xFF,
3637 0x00, 0x00, 0x00, 0x03, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC2, 0xE8, 0xFF, 0xFF, 0x04, 0x00,
3638 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE8, 0xFF, 0xFF,
3643 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00,
3644 0x00, 0x00, 0x36, 0xE8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3645 0x46, 0xE9, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3663 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3690 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3693 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3694 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3695 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3696 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3700 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3703 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3704 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3705 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3706 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3707 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3708 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3709 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x52, 0xED, 0xFF, 0xFF,
3717 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00,
3718 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6E, 0xED, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x14, 0x05, 0x00, 0x00,
3719 0x04, 0x00, 0x00, 0x00, 0x7E, 0xEE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00,
3720 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3721 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3722 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3725 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3726 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3727 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3728 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3729 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3730 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3732 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3733 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3734 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3735 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3736 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3737 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3738 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3739 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3740 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3741 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3743 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3744 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3745 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3746 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3755 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3785 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 0x8A, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3792 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xA6, 0xF2, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03,
3793 0x14, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB6, 0xF3, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x40, 0x01,
3794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3797 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3805 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3819 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3836 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3848 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3849 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3850 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3851 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3856 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3859 0x00, 0x00, 0x00, 0x00, 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, 0xC2, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3866 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xDE, 0xF7, 0xFF, 0xFF,
3867 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xEE, 0xF8, 0xFF, 0xFF, 0x04, 0x00,
3868 0x00, 0x00, 0x64, 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, 0x8A, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
3891 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00,
3892 0x00, 0x00, 0xA6, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3893 0xB6, 0xFA, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 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, 0x52, 0xFB,
3916 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
3917 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6E, 0xFB, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xA4, 0x01,
3918 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7E, 0xFC, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
3919 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3920 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3921 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3922 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3923 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3924 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3925 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3927 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3929 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3930 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3931 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3932 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3933 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3935 0x00, 0x00, 0x00, 0x00, 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, 0x1A, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3942 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x00,
3943 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
3944 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x2E, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3945 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6C, 0x73,
3946 0x74, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00,
3947 0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x30, 0x00,
3948 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3949 0xA6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3950 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
3951 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3952 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x64, 0xFF, 0xFF, 0xFF,
3953 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3954 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3955 0xB4, 0xFE, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x1A, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3956 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
3957 0xF0, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
3958 0x10, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
3959 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
3960 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
3961 0x7E, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00,
3962 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x76, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
3963 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
3964 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
3965 0x68, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0xCE, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00,
3966 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
3967 0x08, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0C, 0x00,
3968 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
3969 0x08, 0x00, 0x0E, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00,
3970 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x14, 0x00,
3971 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
3972 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3973 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
3974 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6E, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
3975 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00,
3976 0x0C, 0x00, 0x07, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00,
3977 0xF6, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x04, 0x00, 0x06, 0x00,
3978 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
3979 0x0C, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
3980 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3981 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,
3982 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0C, 0x00,
3983 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
3984 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00
3985 };
3986
3987 armnn::INetworkPtr deserializedNetwork =
3988 DeserializeNetwork(std::string(lstmNoCifgWithPeepholeAndProjectionModel.begin(),
3989 lstmNoCifgWithPeepholeAndProjectionModel.end()));
3990
Jan Eilersf8c62972019-07-17 11:07:49 +01003991 BOOST_CHECK(deserializedNetwork);
3992
3993 // generating the same model parameters which where used to serialize the model (Layer norm is not specified)
3994 armnn::LstmDescriptor descriptor;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003995 descriptor.m_ActivationFunc = 4;
Jan Eilersf8c62972019-07-17 11:07:49 +01003996 descriptor.m_ClippingThresProj = 0.0f;
3997 descriptor.m_ClippingThresCell = 0.0f;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01003998 descriptor.m_CifgEnabled = false;
Jan Eilersf8c62972019-07-17 11:07:49 +01003999 descriptor.m_ProjectionEnabled = true;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004000 descriptor.m_PeepholeEnabled = true;
Jan Eilersf8c62972019-07-17 11:07:49 +01004001
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004002 const uint32_t batchSize = 2u;
4003 const uint32_t inputSize = 5u;
4004 const uint32_t numUnits = 20u;
4005 const uint32_t outputSize = 16u;
Jan Eilersf8c62972019-07-17 11:07:49 +01004006
4007 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
4008 std::vector<float> inputToInputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4009 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
4010
4011 std::vector<float> inputToForgetWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4012 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
4013
4014 std::vector<float> inputToCellWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4015 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
4016
4017 std::vector<float> inputToOutputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4018 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
4019
4020 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
4021 std::vector<float> inputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4022 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
4023
4024 std::vector<float> forgetGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4025 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
4026
4027 std::vector<float> cellBiasData(tensorInfo20.GetNumElements(), 0.0f);
4028 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
4029
4030 std::vector<float> outputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4031 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
4032
4033 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
4034 std::vector<float> recurrentToInputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4035 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
4036
4037 std::vector<float> recurrentToForgetWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4038 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
4039
4040 std::vector<float> recurrentToCellWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4041 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
4042
4043 std::vector<float> recurrentToOutputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4044 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
4045
4046 std::vector<float> cellToInputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4047 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
4048
4049 std::vector<float> cellToForgetWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4050 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
4051
4052 std::vector<float> cellToOutputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4053 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
4054
4055 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
4056 std::vector<float> projectionWeightsData(tensorInfo16x20.GetNumElements(), 0.0f);
4057 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
4058
4059 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
4060 std::vector<float> projectionBiasData(outputSize, 0.0f);
4061 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
4062
4063 armnn::LstmInputParams params;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004064 params.m_InputToForgetWeights = &inputToForgetWeights;
4065 params.m_InputToCellWeights = &inputToCellWeights;
4066 params.m_InputToOutputWeights = &inputToOutputWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004067 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004068 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004069 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004070 params.m_ForgetGateBias = &forgetGateBias;
4071 params.m_CellBias = &cellBias;
4072 params.m_OutputGateBias = &outputGateBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004073
4074 // additional params because: descriptor.m_CifgEnabled = false
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004075 params.m_InputToInputWeights = &inputToInputWeights;
4076 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4077 params.m_CellToInputWeights = &cellToInputWeights;
4078 params.m_InputGateBias = &inputGateBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004079
4080 // additional params because: descriptor.m_ProjectionEnabled = true
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004081 params.m_ProjectionWeights = &projectionWeights;
4082 params.m_ProjectionBias = &projectionBias;
Jan Eilersf8c62972019-07-17 11:07:49 +01004083
4084 // additional params because: descriptor.m_PeepholeEnabled = true
Aron Virginas-Tar6e0d9622019-10-22 16:24:48 +01004085 params.m_CellToForgetWeights = &cellToForgetWeights;
4086 params.m_CellToOutputWeights = &cellToOutputWeights;
Jan Eilersf8c62972019-07-17 11:07:49 +01004087
4088 const std::string layerName("lstm");
4089 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
4090 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
4091 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
4092 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
4093
Jan Eilersf8c62972019-07-17 11:07:49 +01004094 VerifyLstmLayer checker(
4095 layerName,
4096 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
4097 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4098 descriptor,
4099 params);
4100 deserializedNetwork->Accept(checker);
4101}
Jan Eilers5b01a892019-07-23 09:47:43 +01004102class VerifyQuantizedLstmLayer : public LayerVerifierBase
4103{
4104
4105public:
4106 VerifyQuantizedLstmLayer(const std::string& layerName,
4107 const std::vector<armnn::TensorInfo>& inputInfos,
4108 const std::vector<armnn::TensorInfo>& outputInfos,
Aron Virginas-Tare80ebd12019-10-17 16:11:54 +01004109 const armnn::QuantizedLstmInputParams& inputParams)
4110 : LayerVerifierBase(layerName, inputInfos, outputInfos), m_InputParams(inputParams) {}
Jan Eilers5b01a892019-07-23 09:47:43 +01004111
4112 void VisitQuantizedLstmLayer(const armnn::IConnectableLayer* layer,
4113 const armnn::QuantizedLstmInputParams& params,
4114 const char* name)
4115 {
4116 VerifyNameAndConnections(layer, name);
4117 VerifyInputParameters(params);
4118 }
4119
4120protected:
4121 void VerifyInputParameters(const armnn::QuantizedLstmInputParams& params)
4122 {
4123 VerifyConstTensors("m_InputToInputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004124 m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004125 VerifyConstTensors("m_InputToForgetWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004126 m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004127 VerifyConstTensors("m_InputToCellWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004128 m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004129 VerifyConstTensors("m_InputToOutputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004130 m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004131 VerifyConstTensors("m_RecurrentToInputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004132 m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004133 VerifyConstTensors("m_RecurrentToForgetWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004134 m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004135 VerifyConstTensors("m_RecurrentToCellWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004136 m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004137 VerifyConstTensors("m_RecurrentToOutputWeights",
alanhsu567886324fc2019-10-25 23:44:16 +08004138 m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
Jan Eilers5b01a892019-07-23 09:47:43 +01004139 VerifyConstTensors("m_InputGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004140 m_InputParams.m_InputGateBias, params.m_InputGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004141 VerifyConstTensors("m_ForgetGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004142 m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004143 VerifyConstTensors("m_CellBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004144 m_InputParams.m_CellBias, params.m_CellBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004145 VerifyConstTensors("m_OutputGateBias",
alanhsu567886324fc2019-10-25 23:44:16 +08004146 m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
Jan Eilers5b01a892019-07-23 09:47:43 +01004147 }
4148
4149private:
4150 armnn::QuantizedLstmInputParams m_InputParams;
4151};
4152
4153BOOST_AUTO_TEST_CASE(SerializeDeserializeQuantizedLstm)
4154{
4155 const uint32_t batchSize = 1;
4156 const uint32_t inputSize = 2;
4157 const uint32_t numUnits = 4;
4158 const uint32_t outputSize = numUnits;
4159
alanhsu567886324fc2019-10-25 23:44:16 +08004160 // Scale/Offset for input/output, cellState In/Out, weights, bias
4161 float inputOutputScale = 0.0078125f;
4162 int32_t inputOutputOffset = 128;
Jan Eilers5b01a892019-07-23 09:47:43 +01004163
alanhsu567886324fc2019-10-25 23:44:16 +08004164 float cellStateScale = 0.00048828125f;
4165 int32_t cellStateOffset = 0;
Jan Eilers5b01a892019-07-23 09:47:43 +01004166
alanhsu567886324fc2019-10-25 23:44:16 +08004167 float weightsScale = 0.00408021f;
4168 int32_t weightsOffset = 100;
Jan Eilers5b01a892019-07-23 09:47:43 +01004169
alanhsu567886324fc2019-10-25 23:44:16 +08004170 float biasScale = 3.1876640625e-05f;
4171 int32_t biasOffset = 0;
Jan Eilers5b01a892019-07-23 09:47:43 +01004172
alanhsu567886324fc2019-10-25 23:44:16 +08004173 // The shape of weight data is {outputSize, inputSize} = {4, 2}
4174 armnn::TensorShape inputToInputWeightsShape = {4, 2};
4175 std::vector<uint8_t> inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4176 armnn::TensorInfo inputToInputWeightsInfo(inputToInputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004177 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004178 weightsScale,
4179 weightsOffset);
4180 armnn::ConstTensor inputToInputWeights(inputToInputWeightsInfo, inputToInputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004181
alanhsu567886324fc2019-10-25 23:44:16 +08004182 armnn::TensorShape inputToForgetWeightsShape = {4, 2};
4183 std::vector<uint8_t> inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4184 armnn::TensorInfo inputToForgetWeightsInfo(inputToForgetWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004185 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004186 weightsScale,
4187 weightsOffset);
4188 armnn::ConstTensor inputToForgetWeights(inputToForgetWeightsInfo, inputToForgetWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004189
alanhsu567886324fc2019-10-25 23:44:16 +08004190 armnn::TensorShape inputToCellWeightsShape = {4, 2};
4191 std::vector<uint8_t> inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4192 armnn::TensorInfo inputToCellWeightsInfo(inputToCellWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004193 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004194 weightsScale,
4195 weightsOffset);
4196 armnn::ConstTensor inputToCellWeights(inputToCellWeightsInfo, inputToCellWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004197
alanhsu567886324fc2019-10-25 23:44:16 +08004198 armnn::TensorShape inputToOutputWeightsShape = {4, 2};
4199 std::vector<uint8_t> inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8};
4200 armnn::TensorInfo inputToOutputWeightsInfo(inputToOutputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004201 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004202 weightsScale,
4203 weightsOffset);
4204 armnn::ConstTensor inputToOutputWeights(inputToOutputWeightsInfo, inputToOutputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004205
alanhsu567886324fc2019-10-25 23:44:16 +08004206 // The shape of recurrent weight data is {outputSize, outputSize} = {4, 4}
4207 armnn::TensorShape recurrentToInputWeightsShape = {4, 4};
4208 std::vector<uint8_t> recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4209 armnn::TensorInfo recurrentToInputWeightsInfo(recurrentToInputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004210 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004211 weightsScale,
4212 weightsOffset);
4213 armnn::ConstTensor recurrentToInputWeights(recurrentToInputWeightsInfo, recurrentToInputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004214
alanhsu567886324fc2019-10-25 23:44:16 +08004215 armnn::TensorShape recurrentToForgetWeightsShape = {4, 4};
4216 std::vector<uint8_t> recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4217 armnn::TensorInfo recurrentToForgetWeightsInfo(recurrentToForgetWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004218 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004219 weightsScale,
4220 weightsOffset);
4221 armnn::ConstTensor recurrentToForgetWeights(recurrentToForgetWeightsInfo, recurrentToForgetWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004222
alanhsu567886324fc2019-10-25 23:44:16 +08004223 armnn::TensorShape recurrentToCellWeightsShape = {4, 4};
4224 std::vector<uint8_t> recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4225 armnn::TensorInfo recurrentToCellWeightsInfo(recurrentToCellWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004226 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004227 weightsScale,
4228 weightsOffset);
4229 armnn::ConstTensor recurrentToCellWeights(recurrentToCellWeightsInfo, recurrentToCellWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004230
alanhsu567886324fc2019-10-25 23:44:16 +08004231 armnn::TensorShape recurrentToOutputWeightsShape = {4, 4};
4232 std::vector<uint8_t> recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
4233 armnn::TensorInfo recurrentToOutputWeightsInfo(recurrentToOutputWeightsShape,
Derek Lambertif90c56d2020-01-10 17:14:08 +00004234 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004235 weightsScale,
4236 weightsOffset);
4237 armnn::ConstTensor recurrentToOutputWeights(recurrentToOutputWeightsInfo, recurrentToOutputWeightsData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004238
alanhsu567886324fc2019-10-25 23:44:16 +08004239 // The shape of bias data is {outputSize} = {4}
4240 armnn::TensorShape inputGateBiasShape = {4};
4241 std::vector<int32_t> inputGateBiasData = {1, 2, 3, 4};
4242 armnn::TensorInfo inputGateBiasInfo(inputGateBiasShape,
4243 armnn::DataType::Signed32,
4244 biasScale,
4245 biasOffset);
4246 armnn::ConstTensor inputGateBias(inputGateBiasInfo, inputGateBiasData);
4247
4248 armnn::TensorShape forgetGateBiasShape = {4};
4249 std::vector<int32_t> forgetGateBiasData = {1, 2, 3, 4};
4250 armnn::TensorInfo forgetGateBiasInfo(forgetGateBiasShape,
4251 armnn::DataType::Signed32,
4252 biasScale,
4253 biasOffset);
4254 armnn::ConstTensor forgetGateBias(forgetGateBiasInfo, forgetGateBiasData);
4255
4256 armnn::TensorShape cellBiasShape = {4};
4257 std::vector<int32_t> cellBiasData = {1, 2, 3, 4};
4258 armnn::TensorInfo cellBiasInfo(cellBiasShape,
4259 armnn::DataType::Signed32,
4260 biasScale,
4261 biasOffset);
4262 armnn::ConstTensor cellBias(cellBiasInfo, cellBiasData);
4263
4264 armnn::TensorShape outputGateBiasShape = {4};
4265 std::vector<int32_t> outputGateBiasData = {1, 2, 3, 4};
4266 armnn::TensorInfo outputGateBiasInfo(outputGateBiasShape,
4267 armnn::DataType::Signed32,
4268 biasScale,
4269 biasOffset);
4270 armnn::ConstTensor outputGateBias(outputGateBiasInfo, outputGateBiasData);
Jan Eilers5b01a892019-07-23 09:47:43 +01004271
4272 armnn::QuantizedLstmInputParams params;
4273 params.m_InputToInputWeights = &inputToInputWeights;
4274 params.m_InputToForgetWeights = &inputToForgetWeights;
4275 params.m_InputToCellWeights = &inputToCellWeights;
4276 params.m_InputToOutputWeights = &inputToOutputWeights;
4277 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4278 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4279 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4280 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4281 params.m_InputGateBias = &inputGateBias;
4282 params.m_ForgetGateBias = &forgetGateBias;
4283 params.m_CellBias = &cellBias;
4284 params.m_OutputGateBias = &outputGateBias;
4285
4286 armnn::INetworkPtr network = armnn::INetwork::Create();
alanhsu567886324fc2019-10-25 23:44:16 +08004287 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
Jan Eilers5b01a892019-07-23 09:47:43 +01004288 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
4289 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
4290 const std::string layerName("QuantizedLstm");
4291 armnn::IConnectableLayer* const quantizedLstmLayer = network->AddQuantizedLstmLayer(params, layerName.c_str());
alanhsu567886324fc2019-10-25 23:44:16 +08004292 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(0);
4293 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(1);
Jan Eilers5b01a892019-07-23 09:47:43 +01004294
alanhsu567886324fc2019-10-25 23:44:16 +08004295 // Connect up
4296 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004297 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004298 inputOutputScale,
4299 inputOutputOffset);
4300 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004301 armnn::DataType::QSymmS16,
alanhsu567886324fc2019-10-25 23:44:16 +08004302 cellStateScale,
4303 cellStateOffset);
4304 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize },
Derek Lambertif90c56d2020-01-10 17:14:08 +00004305 armnn::DataType::QAsymmU8,
alanhsu567886324fc2019-10-25 23:44:16 +08004306 inputOutputScale,
4307 inputOutputOffset);
Jan Eilers5b01a892019-07-23 09:47:43 +01004308
4309 inputLayer->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(0));
4310 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
4311
4312 cellStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(1));
4313 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4314
4315 outputStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(2));
4316 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
4317
4318 quantizedLstmLayer->GetOutputSlot(0).Connect(cellStateOut->GetInputSlot(0));
4319 quantizedLstmLayer->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4320
4321 quantizedLstmLayer->GetOutputSlot(1).Connect(outputLayer->GetInputSlot(0));
4322 quantizedLstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
4323
4324 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4325 BOOST_CHECK(deserializedNetwork);
4326
alanhsu567886324fc2019-10-25 23:44:16 +08004327 VerifyQuantizedLstmLayer checker(layerName,
4328 {inputTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4329 {cellStateTensorInfo, outputStateTensorInfo},
4330 params);
Jan Eilers5b01a892019-07-23 09:47:43 +01004331
4332 deserializedNetwork->Accept(checker);
4333}
4334
James Conroy8d333182020-05-13 10:27:58 +01004335class VerifyQLstmLayer : public LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>
4336{
4337public:
4338 VerifyQLstmLayer(const std::string& layerName,
4339 const std::vector<armnn::TensorInfo>& inputInfos,
4340 const std::vector<armnn::TensorInfo>& outputInfos,
4341 const armnn::QLstmDescriptor& descriptor,
4342 const armnn::LstmInputParams& inputParams)
4343 : LayerVerifierBaseWithDescriptor<armnn::QLstmDescriptor>(layerName, inputInfos, outputInfos, descriptor)
4344 , m_InputParams(inputParams) {}
4345
4346 void VisitQLstmLayer(const armnn::IConnectableLayer* layer,
4347 const armnn::QLstmDescriptor& descriptor,
4348 const armnn::LstmInputParams& params,
4349 const char* name)
4350 {
4351 VerifyNameAndConnections(layer, name);
4352 VerifyDescriptor(descriptor);
4353 VerifyInputParameters(params);
4354 }
4355
4356protected:
4357 void VerifyInputParameters(const armnn::LstmInputParams& params)
4358 {
4359 VerifyConstTensors(
4360 "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4361 VerifyConstTensors(
4362 "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4363 VerifyConstTensors(
4364 "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4365 VerifyConstTensors(
4366 "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4367 VerifyConstTensors(
4368 "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4369 VerifyConstTensors(
4370 "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4371 VerifyConstTensors(
4372 "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4373 VerifyConstTensors(
4374 "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4375 VerifyConstTensors(
4376 "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
4377 VerifyConstTensors(
4378 "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
4379 VerifyConstTensors(
4380 "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
4381 VerifyConstTensors(
4382 "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
4383 VerifyConstTensors(
4384 "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4385 VerifyConstTensors(
4386 "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
4387 VerifyConstTensors(
4388 "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4389 VerifyConstTensors(
4390 "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
4391 VerifyConstTensors(
4392 "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
4393 VerifyConstTensors(
4394 "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
4395 VerifyConstTensors(
4396 "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
4397 VerifyConstTensors(
4398 "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
4399 VerifyConstTensors(
4400 "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
4401 }
4402
4403private:
4404 armnn::LstmInputParams m_InputParams;
4405};
4406
4407BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmBasic)
4408{
4409 armnn::QLstmDescriptor descriptor;
4410
4411 descriptor.m_CifgEnabled = true;
4412 descriptor.m_ProjectionEnabled = false;
4413 descriptor.m_PeepholeEnabled = false;
4414 descriptor.m_LayerNormEnabled = false;
4415
4416 descriptor.m_CellClip = 0.0f;
4417 descriptor.m_ProjectionClip = 0.0f;
4418
4419 descriptor.m_InputIntermediateScale = 0.00001f;
4420 descriptor.m_ForgetIntermediateScale = 0.00001f;
4421 descriptor.m_CellIntermediateScale = 0.00001f;
4422 descriptor.m_OutputIntermediateScale = 0.00001f;
4423
4424 descriptor.m_HiddenStateScale = 0.07f;
4425 descriptor.m_HiddenStateZeroPoint = 0;
4426
4427 const unsigned int numBatches = 2;
4428 const unsigned int inputSize = 5;
4429 const unsigned int outputSize = 4;
4430 const unsigned int numUnits = 4;
4431
4432 // Scale/Offset quantization info
4433 float inputScale = 0.0078f;
4434 int32_t inputOffset = 0;
4435
4436 float outputScale = 0.0078f;
4437 int32_t outputOffset = 0;
4438
4439 float cellStateScale = 3.5002e-05f;
4440 int32_t cellStateOffset = 0;
4441
4442 float weightsScale = 0.007f;
4443 int32_t weightsOffset = 0;
4444
4445 float biasScale = 3.5002e-05f / 1024;
4446 int32_t biasOffset = 0;
4447
4448 // Weights and bias tensor and quantization info
4449 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4450 armnn::DataType::QSymmS8,
4451 weightsScale,
4452 weightsOffset);
4453
4454 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4455 armnn::DataType::QSymmS8,
4456 weightsScale,
4457 weightsOffset);
4458
4459 armnn::TensorInfo biasInfo({numUnits}, armnn::DataType::Signed32, biasScale, biasOffset);
4460
4461 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4462 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4463 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4464
4465 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4466 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4467 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4468
4469 std::vector<int8_t> recurrentToForgetWeightsData =
4470 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4471 std::vector<int8_t> recurrentToCellWeightsData =
4472 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4473 std::vector<int8_t> recurrentToOutputWeightsData =
4474 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4475
4476 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4477 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4478 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4479
4480 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4481 std::vector<int32_t> cellBiasData(numUnits, 0);
4482 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4483
4484 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4485 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4486 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4487
4488 // Set up params
4489 armnn::LstmInputParams params;
4490 params.m_InputToForgetWeights = &inputToForgetWeights;
4491 params.m_InputToCellWeights = &inputToCellWeights;
4492 params.m_InputToOutputWeights = &inputToOutputWeights;
4493
4494 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4495 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4496 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4497
4498 params.m_ForgetGateBias = &forgetGateBias;
4499 params.m_CellBias = &cellBias;
4500 params.m_OutputGateBias = &outputGateBias;
4501
4502 // Create network
4503 armnn::INetworkPtr network = armnn::INetwork::Create();
4504 const std::string layerName("qLstm");
4505
4506 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4507 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4508 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4509
4510 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4511
4512 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4513 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4514 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4515
4516 // Input/Output tensor info
4517 armnn::TensorInfo inputInfo({numBatches , inputSize},
4518 armnn::DataType::QAsymmS8,
4519 inputScale,
4520 inputOffset);
4521
4522 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4523 armnn::DataType::QSymmS16,
4524 cellStateScale,
4525 cellStateOffset);
4526
4527 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4528 armnn::DataType::QAsymmS8,
4529 outputScale,
4530 outputOffset);
4531
4532 // Connect input/output slots
4533 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4534 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4535
4536 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4537 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4538
4539 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4540 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4541
4542 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4543 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4544
4545 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4546 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4547
4548 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4549 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4550
4551 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4552 BOOST_CHECK(deserializedNetwork);
4553
4554 VerifyQLstmLayer checker(layerName,
4555 {inputInfo, cellStateInfo, outputStateInfo},
4556 {outputStateInfo, cellStateInfo, outputStateInfo},
4557 descriptor,
4558 params);
4559
4560 deserializedNetwork->Accept(checker);
4561}
4562
4563BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmCifgLayerNorm)
4564{
4565 armnn::QLstmDescriptor descriptor;
4566
4567 // CIFG params are used when CIFG is disabled
4568 descriptor.m_CifgEnabled = true;
4569 descriptor.m_ProjectionEnabled = false;
4570 descriptor.m_PeepholeEnabled = false;
4571 descriptor.m_LayerNormEnabled = true;
4572
4573 descriptor.m_CellClip = 0.0f;
4574 descriptor.m_ProjectionClip = 0.0f;
4575
4576 descriptor.m_InputIntermediateScale = 0.00001f;
4577 descriptor.m_ForgetIntermediateScale = 0.00001f;
4578 descriptor.m_CellIntermediateScale = 0.00001f;
4579 descriptor.m_OutputIntermediateScale = 0.00001f;
4580
4581 descriptor.m_HiddenStateScale = 0.07f;
4582 descriptor.m_HiddenStateZeroPoint = 0;
4583
4584 const unsigned int numBatches = 2;
4585 const unsigned int inputSize = 5;
4586 const unsigned int outputSize = 4;
4587 const unsigned int numUnits = 4;
4588
4589 // Scale/Offset quantization info
4590 float inputScale = 0.0078f;
4591 int32_t inputOffset = 0;
4592
4593 float outputScale = 0.0078f;
4594 int32_t outputOffset = 0;
4595
4596 float cellStateScale = 3.5002e-05f;
4597 int32_t cellStateOffset = 0;
4598
4599 float weightsScale = 0.007f;
4600 int32_t weightsOffset = 0;
4601
4602 float layerNormScale = 3.5002e-05f;
4603 int32_t layerNormOffset = 0;
4604
4605 float biasScale = layerNormScale / 1024;
4606 int32_t biasOffset = 0;
4607
4608 // Weights and bias tensor and quantization info
4609 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4610 armnn::DataType::QSymmS8,
4611 weightsScale,
4612 weightsOffset);
4613
4614 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4615 armnn::DataType::QSymmS8,
4616 weightsScale,
4617 weightsOffset);
4618
4619 armnn::TensorInfo biasInfo({numUnits},
4620 armnn::DataType::Signed32,
4621 biasScale,
4622 biasOffset);
4623
4624 armnn::TensorInfo layerNormWeightsInfo({numUnits},
4625 armnn::DataType::QSymmS16,
4626 layerNormScale,
4627 layerNormOffset);
4628
4629 // Mandatory params
4630 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4631 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4632 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4633
4634 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4635 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4636 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4637
4638 std::vector<int8_t> recurrentToForgetWeightsData =
4639 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4640 std::vector<int8_t> recurrentToCellWeightsData =
4641 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4642 std::vector<int8_t> recurrentToOutputWeightsData =
4643 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4644
4645 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4646 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4647 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4648
4649 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4650 std::vector<int32_t> cellBiasData(numUnits, 0);
4651 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4652
4653 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4654 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4655 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4656
4657 // Layer Norm
4658 std::vector<int16_t> forgetLayerNormWeightsData =
4659 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4660 std::vector<int16_t> cellLayerNormWeightsData =
4661 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4662 std::vector<int16_t> outputLayerNormWeightsData =
4663 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4664
4665 armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
4666 armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
4667 armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
4668
4669 // Set up params
4670 armnn::LstmInputParams params;
4671
4672 // Mandatory params
4673 params.m_InputToForgetWeights = &inputToForgetWeights;
4674 params.m_InputToCellWeights = &inputToCellWeights;
4675 params.m_InputToOutputWeights = &inputToOutputWeights;
4676
4677 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4678 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4679 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4680
4681 params.m_ForgetGateBias = &forgetGateBias;
4682 params.m_CellBias = &cellBias;
4683 params.m_OutputGateBias = &outputGateBias;
4684
4685 // Layer Norm
4686 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
4687 params.m_CellLayerNormWeights = &cellLayerNormWeights;
4688 params.m_OutputLayerNormWeights = &outputLayerNormWeights;
4689
4690 // Create network
4691 armnn::INetworkPtr network = armnn::INetwork::Create();
4692 const std::string layerName("qLstm");
4693
4694 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4695 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4696 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4697
4698 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4699
4700 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4701 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4702 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4703
4704 // Input/Output tensor info
4705 armnn::TensorInfo inputInfo({numBatches , inputSize},
4706 armnn::DataType::QAsymmS8,
4707 inputScale,
4708 inputOffset);
4709
4710 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4711 armnn::DataType::QSymmS16,
4712 cellStateScale,
4713 cellStateOffset);
4714
4715 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4716 armnn::DataType::QAsymmS8,
4717 outputScale,
4718 outputOffset);
4719
4720 // Connect input/output slots
4721 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4722 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4723
4724 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4725 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4726
4727 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4728 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4729
4730 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4731 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4732
4733 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4734 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4735
4736 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4737 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4738
4739 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4740 BOOST_CHECK(deserializedNetwork);
4741
4742 VerifyQLstmLayer checker(layerName,
4743 {inputInfo, cellStateInfo, outputStateInfo},
4744 {outputStateInfo, cellStateInfo, outputStateInfo},
4745 descriptor,
4746 params);
4747
4748 deserializedNetwork->Accept(checker);
4749}
4750
4751BOOST_AUTO_TEST_CASE(SerializeDeserializeQLstmAdvanced)
4752{
4753 armnn::QLstmDescriptor descriptor;
4754
4755 descriptor.m_CifgEnabled = false;
4756 descriptor.m_ProjectionEnabled = true;
4757 descriptor.m_PeepholeEnabled = true;
4758 descriptor.m_LayerNormEnabled = true;
4759
4760 descriptor.m_CellClip = 0.1f;
4761 descriptor.m_ProjectionClip = 0.1f;
4762
4763 descriptor.m_InputIntermediateScale = 0.00001f;
4764 descriptor.m_ForgetIntermediateScale = 0.00001f;
4765 descriptor.m_CellIntermediateScale = 0.00001f;
4766 descriptor.m_OutputIntermediateScale = 0.00001f;
4767
4768 descriptor.m_HiddenStateScale = 0.07f;
4769 descriptor.m_HiddenStateZeroPoint = 0;
4770
4771 const unsigned int numBatches = 2;
4772 const unsigned int inputSize = 5;
4773 const unsigned int outputSize = 4;
4774 const unsigned int numUnits = 4;
4775
4776 // Scale/Offset quantization info
4777 float inputScale = 0.0078f;
4778 int32_t inputOffset = 0;
4779
4780 float outputScale = 0.0078f;
4781 int32_t outputOffset = 0;
4782
4783 float cellStateScale = 3.5002e-05f;
4784 int32_t cellStateOffset = 0;
4785
4786 float weightsScale = 0.007f;
4787 int32_t weightsOffset = 0;
4788
4789 float layerNormScale = 3.5002e-05f;
4790 int32_t layerNormOffset = 0;
4791
4792 float biasScale = layerNormScale / 1024;
4793 int32_t biasOffset = 0;
4794
4795 // Weights and bias tensor and quantization info
4796 armnn::TensorInfo inputWeightsInfo({numUnits, inputSize},
4797 armnn::DataType::QSymmS8,
4798 weightsScale,
4799 weightsOffset);
4800
4801 armnn::TensorInfo recurrentWeightsInfo({numUnits, outputSize},
4802 armnn::DataType::QSymmS8,
4803 weightsScale,
4804 weightsOffset);
4805
4806 armnn::TensorInfo biasInfo({numUnits},
4807 armnn::DataType::Signed32,
4808 biasScale,
4809 biasOffset);
4810
4811 armnn::TensorInfo peepholeWeightsInfo({numUnits},
4812 armnn::DataType::QSymmS16,
4813 weightsScale,
4814 weightsOffset);
4815
4816 armnn::TensorInfo layerNormWeightsInfo({numUnits},
4817 armnn::DataType::QSymmS16,
4818 layerNormScale,
4819 layerNormOffset);
4820
4821 armnn::TensorInfo projectionWeightsInfo({outputSize, numUnits},
4822 armnn::DataType::QSymmS8,
4823 weightsScale,
4824 weightsOffset);
4825
4826 // Mandatory params
4827 std::vector<int8_t> inputToForgetWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4828 std::vector<int8_t> inputToCellWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4829 std::vector<int8_t> inputToOutputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4830
4831 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo, inputToForgetWeightsData);
4832 armnn::ConstTensor inputToCellWeights(inputWeightsInfo, inputToCellWeightsData);
4833 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo, inputToOutputWeightsData);
4834
4835 std::vector<int8_t> recurrentToForgetWeightsData =
4836 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4837 std::vector<int8_t> recurrentToCellWeightsData =
4838 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4839 std::vector<int8_t> recurrentToOutputWeightsData =
4840 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4841
4842 armnn::ConstTensor recurrentToForgetWeights(recurrentWeightsInfo, recurrentToForgetWeightsData);
4843 armnn::ConstTensor recurrentToCellWeights(recurrentWeightsInfo, recurrentToCellWeightsData);
4844 armnn::ConstTensor recurrentToOutputWeights(recurrentWeightsInfo, recurrentToOutputWeightsData);
4845
4846 std::vector<int32_t> forgetGateBiasData(numUnits, 1);
4847 std::vector<int32_t> cellBiasData(numUnits, 0);
4848 std::vector<int32_t> outputGateBiasData(numUnits, 0);
4849
4850 armnn::ConstTensor forgetGateBias(biasInfo, forgetGateBiasData);
4851 armnn::ConstTensor cellBias(biasInfo, cellBiasData);
4852 armnn::ConstTensor outputGateBias(biasInfo, outputGateBiasData);
4853
4854 // CIFG
4855 std::vector<int8_t> inputToInputWeightsData = GenerateRandomData<int8_t>(inputWeightsInfo.GetNumElements());
4856 std::vector<int8_t> recurrentToInputWeightsData =
4857 GenerateRandomData<int8_t>(recurrentWeightsInfo.GetNumElements());
4858 std::vector<int32_t> inputGateBiasData(numUnits, 1);
4859
4860 armnn::ConstTensor inputToInputWeights(inputWeightsInfo, inputToInputWeightsData);
4861 armnn::ConstTensor recurrentToInputWeights(recurrentWeightsInfo, recurrentToInputWeightsData);
4862 armnn::ConstTensor inputGateBias(biasInfo, inputGateBiasData);
4863
4864 // Peephole
4865 std::vector<int16_t> cellToInputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4866 std::vector<int16_t> cellToForgetWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4867 std::vector<int16_t> cellToOutputWeightsData = GenerateRandomData<int16_t>(peepholeWeightsInfo.GetNumElements());
4868
4869 armnn::ConstTensor cellToInputWeights(peepholeWeightsInfo, cellToInputWeightsData);
4870 armnn::ConstTensor cellToForgetWeights(peepholeWeightsInfo, cellToForgetWeightsData);
4871 armnn::ConstTensor cellToOutputWeights(peepholeWeightsInfo, cellToOutputWeightsData);
4872
4873 // Projection
4874 std::vector<int8_t> projectionWeightsData = GenerateRandomData<int8_t>(projectionWeightsInfo.GetNumElements());
4875 std::vector<int32_t> projectionBiasData(outputSize, 1);
4876
4877 armnn::ConstTensor projectionWeights(projectionWeightsInfo, projectionWeightsData);
4878 armnn::ConstTensor projectionBias(biasInfo, projectionBiasData);
4879
4880 // Layer Norm
4881 std::vector<int16_t> inputLayerNormWeightsData =
4882 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4883 std::vector<int16_t> forgetLayerNormWeightsData =
4884 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4885 std::vector<int16_t> cellLayerNormWeightsData =
4886 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4887 std::vector<int16_t> outputLayerNormWeightsData =
4888 GenerateRandomData<int16_t>(layerNormWeightsInfo.GetNumElements());
4889
4890 armnn::ConstTensor inputLayerNormWeights(layerNormWeightsInfo, inputLayerNormWeightsData);
4891 armnn::ConstTensor forgetLayerNormWeights(layerNormWeightsInfo, forgetLayerNormWeightsData);
4892 armnn::ConstTensor cellLayerNormWeights(layerNormWeightsInfo, cellLayerNormWeightsData);
4893 armnn::ConstTensor outputLayerNormWeights(layerNormWeightsInfo, outputLayerNormWeightsData);
4894
4895 // Set up params
4896 armnn::LstmInputParams params;
4897
4898 // Mandatory params
4899 params.m_InputToForgetWeights = &inputToForgetWeights;
4900 params.m_InputToCellWeights = &inputToCellWeights;
4901 params.m_InputToOutputWeights = &inputToOutputWeights;
4902
4903 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4904 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4905 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4906
4907 params.m_ForgetGateBias = &forgetGateBias;
4908 params.m_CellBias = &cellBias;
4909 params.m_OutputGateBias = &outputGateBias;
4910
4911 // CIFG
4912 params.m_InputToInputWeights = &inputToInputWeights;
4913 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4914 params.m_InputGateBias = &inputGateBias;
4915
4916 // Peephole
4917 params.m_CellToInputWeights = &cellToInputWeights;
4918 params.m_CellToForgetWeights = &cellToForgetWeights;
4919 params.m_CellToOutputWeights = &cellToOutputWeights;
4920
4921 // Projection
4922 params.m_ProjectionWeights = &projectionWeights;
4923 params.m_ProjectionBias = &projectionBias;
4924
4925 // Layer Norm
4926 params.m_InputLayerNormWeights = &inputLayerNormWeights;
4927 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
4928 params.m_CellLayerNormWeights = &cellLayerNormWeights;
4929 params.m_OutputLayerNormWeights = &outputLayerNormWeights;
4930
4931 // Create network
4932 armnn::INetworkPtr network = armnn::INetwork::Create();
4933 const std::string layerName("qLstm");
4934
4935 armnn::IConnectableLayer* const input = network->AddInputLayer(0);
4936 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(1);
4937 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(2);
4938
4939 armnn::IConnectableLayer* const qLstmLayer = network->AddQLstmLayer(descriptor, params, layerName.c_str());
4940
4941 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(0);
4942 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(1);
4943 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(2);
4944
4945 // Input/Output tensor info
4946 armnn::TensorInfo inputInfo({numBatches , inputSize},
4947 armnn::DataType::QAsymmS8,
4948 inputScale,
4949 inputOffset);
4950
4951 armnn::TensorInfo cellStateInfo({numBatches , numUnits},
4952 armnn::DataType::QSymmS16,
4953 cellStateScale,
4954 cellStateOffset);
4955
4956 armnn::TensorInfo outputStateInfo({numBatches , outputSize},
4957 armnn::DataType::QAsymmS8,
4958 outputScale,
4959 outputOffset);
4960
4961 // Connect input/output slots
4962 input->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(0));
4963 input->GetOutputSlot(0).SetTensorInfo(inputInfo);
4964
4965 outputStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(1));
4966 outputStateIn->GetOutputSlot(0).SetTensorInfo(cellStateInfo);
4967
4968 cellStateIn->GetOutputSlot(0).Connect(qLstmLayer->GetInputSlot(2));
4969 cellStateIn->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4970
4971 qLstmLayer->GetOutputSlot(0).Connect(outputStateOut->GetInputSlot(0));
4972 qLstmLayer->GetOutputSlot(0).SetTensorInfo(outputStateInfo);
4973
4974 qLstmLayer->GetOutputSlot(1).Connect(cellStateOut->GetInputSlot(0));
4975 qLstmLayer->GetOutputSlot(1).SetTensorInfo(cellStateInfo);
4976
4977 qLstmLayer->GetOutputSlot(2).Connect(outputLayer->GetInputSlot(0));
4978 qLstmLayer->GetOutputSlot(2).SetTensorInfo(outputStateInfo);
4979
4980 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4981 BOOST_CHECK(deserializedNetwork);
4982
4983 VerifyQLstmLayer checker(layerName,
4984 {inputInfo, cellStateInfo, outputStateInfo},
4985 {outputStateInfo, cellStateInfo, outputStateInfo},
4986 descriptor,
4987 params);
4988
4989 deserializedNetwork->Accept(checker);
4990}
4991
Nattapat Chaimanowong30b00202019-02-20 17:31:34 +00004992BOOST_AUTO_TEST_SUITE_END()