blob: 98893a59cf70110cf8e89ab094b38b0738549dcb [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
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00008#include <armnn/ArmNN.hpp>
9#include <armnn/INetwork.hpp>
Derek Lamberti0028d1b2019-02-20 13:57:42 +000010#include <armnnDeserializer/IDeserializer.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000011
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +000012#include <random>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000013#include <vector>
14
Mike Kelly8c1701a2019-02-11 17:01:27 +000015#include <boost/test/unit_test.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000016
Derek Lamberti0028d1b2019-02-20 13:57:42 +000017using armnnDeserializer::IDeserializer;
Mike Kelly8c1701a2019-02-11 17:01:27 +000018
Saoirse Stewart3166c3e2019-02-18 15:24:53 +000019namespace
20{
21
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000022struct DefaultLayerVerifierPolicy
23{
Les Belle0ca8612019-05-17 16:17:12 +010024 static void Apply(const std::string s = "")
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000025 {
26 BOOST_TEST_MESSAGE("Unexpected layer found in network");
27 BOOST_TEST(false);
28 }
29};
30
31class LayerVerifierBase : public armnn::LayerVisitorBase<DefaultLayerVerifierPolicy>
32{
33public:
34 LayerVerifierBase(const std::string& layerName,
35 const std::vector<armnn::TensorInfo>& inputInfos,
36 const std::vector<armnn::TensorInfo>& outputInfos)
37 : m_LayerName(layerName)
38 , m_InputTensorInfos(inputInfos)
39 , m_OutputTensorInfos(outputInfos) {}
40
41 void VisitInputLayer(const armnn::IConnectableLayer*, armnn::LayerBindingId, const char*) override {}
42
43 void VisitOutputLayer(const armnn::IConnectableLayer*, armnn::LayerBindingId id, const char*) override {}
44
45protected:
46 void VerifyNameAndConnections(const armnn::IConnectableLayer* layer, const char* name)
47 {
48 BOOST_TEST(name == m_LayerName.c_str());
49
50 BOOST_TEST(layer->GetNumInputSlots() == m_InputTensorInfos.size());
51 BOOST_TEST(layer->GetNumOutputSlots() == m_OutputTensorInfos.size());
52
53 for (unsigned int i = 0; i < m_InputTensorInfos.size(); i++)
54 {
55 const armnn::IOutputSlot* connectedOutput = layer->GetInputSlot(i).GetConnection();
56 BOOST_CHECK(connectedOutput);
57
58 const armnn::TensorInfo& connectedInfo = connectedOutput->GetTensorInfo();
59 BOOST_TEST(connectedInfo.GetShape() == m_InputTensorInfos[i].GetShape());
60 BOOST_TEST(
61 GetDataTypeName(connectedInfo.GetDataType()) == GetDataTypeName(m_InputTensorInfos[i].GetDataType()));
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +000062
63 BOOST_TEST(connectedInfo.GetQuantizationScale() == m_InputTensorInfos[i].GetQuantizationScale());
64 BOOST_TEST(connectedInfo.GetQuantizationOffset() == m_InputTensorInfos[i].GetQuantizationOffset());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000065 }
66
67 for (unsigned int i = 0; i < m_OutputTensorInfos.size(); i++)
68 {
69 const armnn::TensorInfo& outputInfo = layer->GetOutputSlot(i).GetTensorInfo();
70 BOOST_TEST(outputInfo.GetShape() == m_OutputTensorInfos[i].GetShape());
71 BOOST_TEST(
72 GetDataTypeName(outputInfo.GetDataType()) == GetDataTypeName(m_OutputTensorInfos[i].GetDataType()));
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +000073
74 BOOST_TEST(outputInfo.GetQuantizationScale() == m_OutputTensorInfos[i].GetQuantizationScale());
75 BOOST_TEST(outputInfo.GetQuantizationOffset() == m_OutputTensorInfos[i].GetQuantizationOffset());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +000076 }
77 }
78
Jan Eilers5b01a892019-07-23 09:47:43 +010079 void VerifyConstTensors(const std::string& tensorName,
80 const armnn::ConstTensor* expectedPtr,
81 const armnn::ConstTensor* actualPtr)
82 {
83 if (expectedPtr == nullptr)
84 {
85 BOOST_CHECK_MESSAGE(actualPtr == nullptr, tensorName + " should not exist");
86 }
87 else
88 {
89 BOOST_CHECK_MESSAGE(actualPtr != nullptr, tensorName + " should have been set");
90 if (actualPtr != nullptr)
91 {
92 const armnn::TensorInfo& expectedInfo = expectedPtr->GetInfo();
93 const armnn::TensorInfo& actualInfo = actualPtr->GetInfo();
94
95 BOOST_CHECK_MESSAGE(expectedInfo.GetShape() == actualInfo.GetShape(),
96 tensorName + " shapes don't match");
97 BOOST_CHECK_MESSAGE(
98 GetDataTypeName(expectedInfo.GetDataType()) == GetDataTypeName(actualInfo.GetDataType()),
99 tensorName + " data types don't match");
100
101 BOOST_CHECK_MESSAGE(expectedPtr->GetNumBytes() == actualPtr->GetNumBytes(),
102 tensorName + " (GetNumBytes) data sizes do not match");
103 if (expectedPtr->GetNumBytes() == actualPtr->GetNumBytes())
104 {
105 //check the data is identical
106 const char* expectedData = static_cast<const char*>(expectedPtr->GetMemoryArea());
107 const char* actualData = static_cast<const char*>(actualPtr->GetMemoryArea());
108 bool same = true;
109 for (unsigned int i = 0; i < expectedPtr->GetNumBytes(); ++i)
110 {
111 same = expectedData[i] == actualData[i];
112 if (!same)
113 {
114 break;
115 }
116 }
117 BOOST_CHECK_MESSAGE(same, tensorName + " data does not match");
118 }
119 }
120 }
121 }
122
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000123private:
124 std::string m_LayerName;
125 std::vector<armnn::TensorInfo> m_InputTensorInfos;
126 std::vector<armnn::TensorInfo> m_OutputTensorInfos;
127};
128
129template<typename T>
130void CompareConstTensorData(const void* data1, const void* data2, unsigned int numElements)
131{
132 T typedData1 = static_cast<T>(data1);
133 T typedData2 = static_cast<T>(data2);
134 BOOST_CHECK(typedData1);
135 BOOST_CHECK(typedData2);
136
137 for (unsigned int i = 0; i < numElements; i++)
138 {
139 BOOST_TEST(typedData1[i] == typedData2[i]);
140 }
141}
142
143void CompareConstTensor(const armnn::ConstTensor& tensor1, const armnn::ConstTensor& tensor2)
144{
145 BOOST_TEST(tensor1.GetShape() == tensor2.GetShape());
146 BOOST_TEST(GetDataTypeName(tensor1.GetDataType()) == GetDataTypeName(tensor2.GetDataType()));
147
148 switch (tensor1.GetDataType())
149 {
150 case armnn::DataType::Float32:
151 CompareConstTensorData<const float*>(
152 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
153 break;
154 case armnn::DataType::QuantisedAsymm8:
155 case armnn::DataType::Boolean:
156 CompareConstTensorData<const uint8_t*>(
157 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
158 break;
159 case armnn::DataType::Signed32:
160 CompareConstTensorData<const int32_t*>(
161 tensor1.GetMemoryArea(), tensor2.GetMemoryArea(), tensor1.GetNumElements());
162 break;
163 default:
164 // Note that Float16 is not yet implemented
165 BOOST_TEST_MESSAGE("Unexpected datatype");
166 BOOST_TEST(false);
167 }
168}
169
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000170armnn::INetworkPtr DeserializeNetwork(const std::string& serializerString)
171{
172 std::vector<std::uint8_t> const serializerVector{serializerString.begin(), serializerString.end()};
Derek Lamberti0028d1b2019-02-20 13:57:42 +0000173 return IDeserializer::Create()->CreateNetworkFromBinary(serializerVector);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000174}
175
176std::string SerializeNetwork(const armnn::INetwork& network)
177{
178 armnnSerializer::Serializer serializer;
179 serializer.Serialize(network);
180
181 std::stringstream stream;
182 serializer.SaveSerializedToStream(stream);
183
184 std::string serializerString{stream.str()};
185 return serializerString;
186}
187
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000188template<typename DataType>
189static std::vector<DataType> GenerateRandomData(size_t size)
190{
191 constexpr bool isIntegerType = std::is_integral<DataType>::value;
192 using Distribution =
193 typename std::conditional<isIntegerType,
194 std::uniform_int_distribution<DataType>,
195 std::uniform_real_distribution<DataType>>::type;
196
197 static constexpr DataType lowerLimit = std::numeric_limits<DataType>::min();
198 static constexpr DataType upperLimit = std::numeric_limits<DataType>::max();
199
200 static Distribution distribution(lowerLimit, upperLimit);
201 static std::default_random_engine generator;
202
203 std::vector<DataType> randomData(size);
204 std::generate(randomData.begin(), randomData.end(), []() { return distribution(generator); });
205
206 return randomData;
207}
208
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000209} // anonymous namespace
210
211BOOST_AUTO_TEST_SUITE(SerializerTests)
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000212
FinnWilliamsArm4ffcc8f2019-09-05 14:34:20 +0100213BOOST_AUTO_TEST_CASE(SerializeAbs)
214{
215 class AbsLayerVerifier : public LayerVerifierBase
216 {
217 public:
218 AbsLayerVerifier(const std::string& layerName,
219 const std::vector<armnn::TensorInfo>& inputInfos,
220 const std::vector<armnn::TensorInfo>& outputInfos)
221 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
222
223 void VisitAbsLayer(const armnn::IConnectableLayer* layer, const char* name) override
224 {
225 VerifyNameAndConnections(layer, name);
226 }
227 };
228
229 const std::string layerName("abs");
230 const armnn::TensorInfo tensorInfo({1, 2, 3}, armnn::DataType::Float32);
231
232 armnn::INetworkPtr network = armnn::INetwork::Create();
233 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
234
235 armnn::IConnectableLayer* const absLayer = network->AddAbsLayer(layerName.c_str());
236 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
237
238 inputLayer->GetOutputSlot(0).Connect(absLayer->GetInputSlot(0));
239 absLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
240
241 inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
242 absLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
243
244 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
245 BOOST_CHECK(deserializedNetwork);
246
247 AbsLayerVerifier verifier(layerName, {tensorInfo}, {tensorInfo});
248 deserializedNetwork->Accept(verifier);
249}
250
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000251BOOST_AUTO_TEST_CASE(SerializeAddition)
Mike Kelly8c1701a2019-02-11 17:01:27 +0000252{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000253 class AdditionLayerVerifier : public LayerVerifierBase
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000254 {
255 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000256 AdditionLayerVerifier(const std::string& layerName,
257 const std::vector<armnn::TensorInfo>& inputInfos,
258 const std::vector<armnn::TensorInfo>& outputInfos)
259 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
260
261 void VisitAdditionLayer(const armnn::IConnectableLayer* layer, const char* name) override
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000262 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000263 VerifyNameAndConnections(layer, name);
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000264 }
265 };
266
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000267 const std::string layerName("addition");
268 const armnn::TensorInfo tensorInfo({1, 2, 3}, armnn::DataType::Float32);
269
Mike Kelly8c1701a2019-02-11 17:01:27 +0000270 armnn::INetworkPtr network = armnn::INetwork::Create();
271 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
272 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000273 armnn::IConnectableLayer* const additionLayer = network->AddAdditionLayer(layerName.c_str());
274 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000275
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000276 inputLayer0->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(0));
277 inputLayer1->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(1));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000278 additionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Mike Kelly8c1701a2019-02-11 17:01:27 +0000279
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000280 inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
281 inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
282 additionLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
Jim Flynn3091b062019-02-15 14:45:04 +0000283
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000284 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000285 BOOST_CHECK(deserializedNetwork);
286
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000287 AdditionLayerVerifier verifier(layerName, {tensorInfo, tensorInfo}, {tensorInfo});
288 deserializedNetwork->Accept(verifier);
289}
Jim Flynnac25a1b2019-02-28 10:40:49 +0000290
Narumol Prangnawarat0cfcf232019-09-09 17:16:24 +0100291BOOST_AUTO_TEST_CASE(SerializeArgMinMax)
292{
293 class ArgMinMaxLayerVerifier : public LayerVerifierBase
294 {
295 public:
296 ArgMinMaxLayerVerifier(const std::string& layerName,
297 const std::vector<armnn::TensorInfo>& inputInfos,
298 const std::vector<armnn::TensorInfo>& outputInfos,
299 const armnn::ArgMinMaxDescriptor& descriptor)
300 : LayerVerifierBase(layerName, inputInfos, outputInfos)
301 , m_Descriptor(descriptor) {}
302
303 void VisitArgMinMaxLayer(const armnn::IConnectableLayer* layer,
304 const armnn::ArgMinMaxDescriptor& descriptor,
305 const char* name) override
306 {
307 VerifyNameAndConnections(layer, name);
308 VerifyDescriptor(descriptor);
309 }
310
311 private:
312 void VerifyDescriptor(const armnn::ArgMinMaxDescriptor& descriptor)
313 {
314 BOOST_CHECK(descriptor.m_Function == m_Descriptor.m_Function);
315 BOOST_CHECK(descriptor.m_Axis == m_Descriptor.m_Axis);
316 }
317
318 armnn::ArgMinMaxDescriptor m_Descriptor;
319 };
320
321 const std::string layerName("argminmax");
322 const armnn::TensorInfo inputInfo({1, 2, 3}, armnn::DataType::Float32);
323 const armnn::TensorInfo outputInfo({1, 3}, armnn::DataType::Signed32);
324
325 armnn::ArgMinMaxDescriptor descriptor;
326 descriptor.m_Function = armnn::ArgMinMaxFunction::Max;
327 descriptor.m_Axis = 1;
328
329 armnn::INetworkPtr network = armnn::INetwork::Create();
330 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
331 armnn::IConnectableLayer* const argMinMaxLayer = network->AddArgMinMaxLayer(descriptor, layerName.c_str());
332 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
333
334 inputLayer->GetOutputSlot(0).Connect(argMinMaxLayer->GetInputSlot(0));
335 argMinMaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
336
337 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
338 argMinMaxLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
339
340 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
341 BOOST_CHECK(deserializedNetwork);
342
343 ArgMinMaxLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
344 deserializedNetwork->Accept(verifier);
345}
346
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000347BOOST_AUTO_TEST_CASE(SerializeBatchNormalization)
348{
349 class BatchNormalizationLayerVerifier : public LayerVerifierBase
350 {
351 public:
352 BatchNormalizationLayerVerifier(const std::string& layerName,
353 const std::vector<armnn::TensorInfo>& inputInfos,
354 const std::vector<armnn::TensorInfo>& outputInfos,
355 const armnn::BatchNormalizationDescriptor& descriptor,
356 const armnn::ConstTensor& mean,
357 const armnn::ConstTensor& variance,
358 const armnn::ConstTensor& beta,
359 const armnn::ConstTensor& gamma)
360 : LayerVerifierBase(layerName, inputInfos, outputInfos)
361 , m_Descriptor(descriptor)
362 , m_Mean(mean)
363 , m_Variance(variance)
364 , m_Beta(beta)
365 , m_Gamma(gamma) {}
366
367 void VisitBatchNormalizationLayer(const armnn::IConnectableLayer* layer,
368 const armnn::BatchNormalizationDescriptor& descriptor,
369 const armnn::ConstTensor& mean,
370 const armnn::ConstTensor& variance,
371 const armnn::ConstTensor& beta,
372 const armnn::ConstTensor& gamma,
373 const char* name) override
374 {
375 VerifyNameAndConnections(layer, name);
376 VerifyDescriptor(descriptor);
377
378 CompareConstTensor(mean, m_Mean);
379 CompareConstTensor(variance, m_Variance);
380 CompareConstTensor(beta, m_Beta);
381 CompareConstTensor(gamma, m_Gamma);
382 }
383
384 private:
385 void VerifyDescriptor(const armnn::BatchNormalizationDescriptor& descriptor)
386 {
387 BOOST_TEST(descriptor.m_Eps == m_Descriptor.m_Eps);
388 BOOST_TEST(static_cast<int>(descriptor.m_DataLayout) == static_cast<int>(m_Descriptor.m_DataLayout));
389 }
390
391 armnn::BatchNormalizationDescriptor m_Descriptor;
392 armnn::ConstTensor m_Mean;
393 armnn::ConstTensor m_Variance;
394 armnn::ConstTensor m_Beta;
395 armnn::ConstTensor m_Gamma;
396 };
397
398 const std::string layerName("batchNormalization");
399 const armnn::TensorInfo inputInfo ({ 1, 3, 3, 1 }, armnn::DataType::Float32);
400 const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
401
402 const armnn::TensorInfo meanInfo({1}, armnn::DataType::Float32);
403 const armnn::TensorInfo varianceInfo({1}, armnn::DataType::Float32);
404 const armnn::TensorInfo betaInfo({1}, armnn::DataType::Float32);
405 const armnn::TensorInfo gammaInfo({1}, armnn::DataType::Float32);
406
407 armnn::BatchNormalizationDescriptor descriptor;
408 descriptor.m_Eps = 0.0010000000475f;
409 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
410
411 std::vector<float> meanData({5.0});
412 std::vector<float> varianceData({2.0});
413 std::vector<float> betaData({1.0});
414 std::vector<float> gammaData({0.0});
415
416 armnn::ConstTensor mean(meanInfo, meanData);
417 armnn::ConstTensor variance(varianceInfo, varianceData);
418 armnn::ConstTensor beta(betaInfo, betaData);
419 armnn::ConstTensor gamma(gammaInfo, gammaData);
420
421 armnn::INetworkPtr network = armnn::INetwork::Create();
422 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
423 armnn::IConnectableLayer* const batchNormalizationLayer =
424 network->AddBatchNormalizationLayer(descriptor, mean, variance, beta, gamma, layerName.c_str());
425 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
426
427 inputLayer->GetOutputSlot(0).Connect(batchNormalizationLayer->GetInputSlot(0));
428 batchNormalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
429
430 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
431 batchNormalizationLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
432
433 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
434 BOOST_CHECK(deserializedNetwork);
435
436 BatchNormalizationLayerVerifier verifier(
437 layerName, {inputInfo}, {outputInfo}, descriptor, mean, variance, beta, gamma);
438 deserializedNetwork->Accept(verifier);
439}
440
441BOOST_AUTO_TEST_CASE(SerializeBatchToSpaceNd)
442{
443 class BatchToSpaceNdLayerVerifier : public LayerVerifierBase
444 {
445 public:
446 BatchToSpaceNdLayerVerifier(const std::string& layerName,
447 const std::vector<armnn::TensorInfo>& inputInfos,
448 const std::vector<armnn::TensorInfo>& outputInfos,
449 const armnn::BatchToSpaceNdDescriptor& descriptor)
450 : LayerVerifierBase(layerName, inputInfos, outputInfos)
451 , m_Descriptor(descriptor) {}
452
453 void VisitBatchToSpaceNdLayer(const armnn::IConnectableLayer* layer,
454 const armnn::BatchToSpaceNdDescriptor& descriptor,
455 const char* name) override
456 {
457 VerifyNameAndConnections(layer, name);
458 VerifyDescriptor(descriptor);
459 }
460
461 private:
462 void VerifyDescriptor(const armnn::BatchToSpaceNdDescriptor& descriptor)
463 {
464 BOOST_TEST(descriptor.m_Crops == m_Descriptor.m_Crops);
465 BOOST_TEST(descriptor.m_BlockShape == m_Descriptor.m_BlockShape);
466 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
467 }
468
469 armnn::BatchToSpaceNdDescriptor m_Descriptor;
470 };
471
472 const std::string layerName("spaceToBatchNd");
473 const armnn::TensorInfo inputInfo({4, 1, 2, 2}, armnn::DataType::Float32);
474 const armnn::TensorInfo outputInfo({1, 1, 4, 4}, armnn::DataType::Float32);
475
476 armnn::BatchToSpaceNdDescriptor desc;
477 desc.m_DataLayout = armnn::DataLayout::NCHW;
478 desc.m_BlockShape = {2, 2};
479 desc.m_Crops = {{0, 0}, {0, 0}};
480
481 armnn::INetworkPtr network = armnn::INetwork::Create();
482 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
483 armnn::IConnectableLayer* const batchToSpaceNdLayer = network->AddBatchToSpaceNdLayer(desc, layerName.c_str());
484 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
485
486 inputLayer->GetOutputSlot(0).Connect(batchToSpaceNdLayer->GetInputSlot(0));
487 batchToSpaceNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
488
489 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
490 batchToSpaceNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
491
492 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
493 BOOST_CHECK(deserializedNetwork);
494
495 BatchToSpaceNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
496 deserializedNetwork->Accept(verifier);
Mike Kelly8c1701a2019-02-11 17:01:27 +0000497}
498
Conor Kennedy76277882019-02-26 08:29:54 +0000499BOOST_AUTO_TEST_CASE(SerializeConstant)
500{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000501 class ConstantLayerVerifier : public LayerVerifierBase
Conor Kennedy76277882019-02-26 08:29:54 +0000502 {
503 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000504 ConstantLayerVerifier(const std::string& layerName,
505 const std::vector<armnn::TensorInfo>& inputInfos,
506 const std::vector<armnn::TensorInfo>& outputInfos,
507 const armnn::ConstTensor& layerInput)
508 : LayerVerifierBase(layerName, inputInfos, outputInfos)
509 , m_LayerInput(layerInput) {}
510
511 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
512 const armnn::ConstTensor& input,
513 const char* name) override
Conor Kennedy76277882019-02-26 08:29:54 +0000514 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000515 VerifyNameAndConnections(layer, name);
516
517 CompareConstTensor(input, m_LayerInput);
Conor Kennedy76277882019-02-26 08:29:54 +0000518 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000519
520 void VisitAdditionLayer(const armnn::IConnectableLayer* layer, const char* name = nullptr) override {}
521
522 private:
523 armnn::ConstTensor m_LayerInput;
Conor Kennedy76277882019-02-26 08:29:54 +0000524 };
525
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000526 const std::string layerName("constant");
527 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
Conor Kennedy76277882019-02-26 08:29:54 +0000528
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000529 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
530 armnn::ConstTensor constTensor(info, constantData);
Conor Kennedy76277882019-02-26 08:29:54 +0000531
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000532 armnn::INetworkPtr network(armnn::INetwork::Create());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000533 armnn::IConnectableLayer* input = network->AddInputLayer(0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000534 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000535 armnn::IConnectableLayer* add = network->AddAdditionLayer();
536 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
Conor Kennedy76277882019-02-26 08:29:54 +0000537
538 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
539 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
540 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
541
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000542 input->GetOutputSlot(0).SetTensorInfo(info);
543 constant->GetOutputSlot(0).SetTensorInfo(info);
544 add->GetOutputSlot(0).SetTensorInfo(info);
Conor Kennedy76277882019-02-26 08:29:54 +0000545
Matteo Martincighf81edaa2019-03-04 14:34:30 +0000546 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Conor Kennedy76277882019-02-26 08:29:54 +0000547 BOOST_CHECK(deserializedNetwork);
548
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000549 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
550 deserializedNetwork->Accept(verifier);
Conor Kennedy76277882019-02-26 08:29:54 +0000551}
552
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000553BOOST_AUTO_TEST_CASE(SerializeConvolution2d)
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000554{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000555 class Convolution2dLayerVerifier : public LayerVerifierBase
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000556 {
557 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000558 Convolution2dLayerVerifier(const std::string& layerName,
559 const std::vector<armnn::TensorInfo>& inputInfos,
560 const std::vector<armnn::TensorInfo>& outputInfos,
561 const armnn::Convolution2dDescriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100562 const armnn::ConstTensor& weights,
563 const armnn::Optional<armnn::ConstTensor>& biases) :
564 LayerVerifierBase(layerName, inputInfos, outputInfos),
565 m_Descriptor(descriptor),
566 m_Weights(weights),
567 m_Biases(biases)
568 {}
Finn Williamsdd2ba7e2019-03-01 11:51:52 +0000569
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000570 void VisitConvolution2dLayer(const armnn::IConnectableLayer* layer,
571 const armnn::Convolution2dDescriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100572 const armnn::ConstTensor& weights,
573 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000574 const char* name) override
575 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000576 VerifyNameAndConnections(layer, name);
577 VerifyDescriptor(descriptor);
578
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100579 // check weights
580 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000581
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100582 // check biases
583 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
584 BOOST_CHECK(m_Biases.has_value() == m_Descriptor.m_BiasEnabled);
585
586 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
587
588 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000589 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100590 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000591 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000592 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000593
594 private:
595 void VerifyDescriptor(const armnn::Convolution2dDescriptor& descriptor)
596 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100597 BOOST_CHECK(descriptor.m_PadLeft == m_Descriptor.m_PadLeft);
598 BOOST_CHECK(descriptor.m_PadRight == m_Descriptor.m_PadRight);
599 BOOST_CHECK(descriptor.m_PadTop == m_Descriptor.m_PadTop);
600 BOOST_CHECK(descriptor.m_PadBottom == m_Descriptor.m_PadBottom);
601 BOOST_CHECK(descriptor.m_StrideX == m_Descriptor.m_StrideX);
602 BOOST_CHECK(descriptor.m_StrideY == m_Descriptor.m_StrideY);
603 BOOST_CHECK(descriptor.m_DilationX == m_Descriptor.m_DilationX);
604 BOOST_CHECK(descriptor.m_DilationY == m_Descriptor.m_DilationY);
605 BOOST_CHECK(descriptor.m_BiasEnabled == m_Descriptor.m_BiasEnabled);
606 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000607 }
608
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100609 armnn::Convolution2dDescriptor m_Descriptor;
610 armnn::ConstTensor m_Weights;
611 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000612 };
613
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000614 const std::string layerName("convolution2d");
615 const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
616 const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
Saoirse Stewart263829c2019-02-19 15:54:14 +0000617
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000618 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
619 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000620
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000621 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
622 armnn::ConstTensor weights(weightsInfo, weightsData);
623
624 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
625 armnn::ConstTensor biases(biasesInfo, biasesData);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000626
627 armnn::Convolution2dDescriptor descriptor;
628 descriptor.m_PadLeft = 1;
629 descriptor.m_PadRight = 1;
630 descriptor.m_PadTop = 1;
631 descriptor.m_PadBottom = 1;
632 descriptor.m_StrideX = 2;
633 descriptor.m_StrideY = 2;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100634 descriptor.m_DilationX = 2;
635 descriptor.m_DilationY = 2;
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000636 descriptor.m_BiasEnabled = true;
637 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
638
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000639 armnn::INetworkPtr network = armnn::INetwork::Create();
640 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000641 armnn::IConnectableLayer* const convLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100642 network->AddConvolution2dLayer(descriptor,
643 weights,
644 armnn::Optional<armnn::ConstTensor>(biases),
645 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000646 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000647
648 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000649 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000650
651 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000652 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
653
654 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
655 BOOST_CHECK(deserializedNetwork);
656
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000657 Convolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
658 deserializedNetwork->Accept(verifier);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000659}
660
Aron Virginas-Tarda9d2d32019-09-20 10:42:02 +0100661BOOST_AUTO_TEST_CASE(SerializeDepthToSpace)
662{
663 class DepthToSpaceLayerVerifier : public LayerVerifierBase
664 {
665 public:
666 DepthToSpaceLayerVerifier(const std::string& layerName,
667 const std::vector<armnn::TensorInfo>& inputInfos,
668 const std::vector<armnn::TensorInfo>& outputInfos,
669 const armnn::DepthToSpaceDescriptor& descriptor)
670 : LayerVerifierBase(layerName, inputInfos, outputInfos)
671 , m_Descriptor(descriptor) {}
672
673 void VisitDepthToSpaceLayer(const armnn::IConnectableLayer* layer,
674 const armnn::DepthToSpaceDescriptor& descriptor,
675 const char* name) override
676 {
677 VerifyNameAndConnections(layer, name);
678 VerifyDescriptor(descriptor);
679 }
680
681 private:
682 void VerifyDescriptor(const armnn::DepthToSpaceDescriptor& descriptor)
683 {
684 BOOST_TEST(descriptor.m_BlockSize == m_Descriptor.m_BlockSize);
685 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
686 }
687
688 armnn::DepthToSpaceDescriptor m_Descriptor;
689 };
690
691 const std::string layerName("depthToSpace");
692
693 const armnn::TensorInfo inputInfo ({ 1, 8, 4, 12 }, armnn::DataType::Float32);
694 const armnn::TensorInfo outputInfo({ 1, 16, 8, 3 }, armnn::DataType::Float32);
695
696 armnn::DepthToSpaceDescriptor desc;
697 desc.m_BlockSize = 2;
698 desc.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 depthToSpaceLayer = network->AddDepthToSpaceLayer(desc, layerName.c_str());
703 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
704
705 inputLayer->GetOutputSlot(0).Connect(depthToSpaceLayer->GetInputSlot(0));
706 depthToSpaceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
707
708 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
709 depthToSpaceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
710
711 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
712 BOOST_CHECK(deserializedNetwork);
713
714 DepthToSpaceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
715 deserializedNetwork->Accept(verifier);
716}
717
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000718BOOST_AUTO_TEST_CASE(SerializeDepthwiseConvolution2d)
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000719{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000720 class DepthwiseConvolution2dLayerVerifier : public LayerVerifierBase
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000721 {
722 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000723 DepthwiseConvolution2dLayerVerifier(const std::string& layerName,
724 const std::vector<armnn::TensorInfo>& inputInfos,
725 const std::vector<armnn::TensorInfo>& outputInfos,
726 const armnn::DepthwiseConvolution2dDescriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100727 const armnn::ConstTensor& weights,
728 const armnn::Optional<armnn::ConstTensor>& biases) :
729 LayerVerifierBase(layerName, inputInfos, outputInfos),
730 m_Descriptor(descriptor),
731 m_Weights(weights),
732 m_Biases(biases)
733 {}
Conor Kennedy79ffdf52019-03-01 14:24:54 +0000734
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000735 void VisitDepthwiseConvolution2dLayer(const armnn::IConnectableLayer* layer,
736 const armnn::DepthwiseConvolution2dDescriptor& descriptor,
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100737 const armnn::ConstTensor& weights,
738 const armnn::Optional<armnn::ConstTensor>& biases,
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000739 const char* name) override
740 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000741 VerifyNameAndConnections(layer, name);
742 VerifyDescriptor(descriptor);
743
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100744 // check weights
745 CompareConstTensor(weights, m_Weights);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000746
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100747 // check biases
748 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
749 BOOST_CHECK(m_Biases.has_value() == m_Descriptor.m_BiasEnabled);
750
751 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
752
753 if (biases.has_value() && m_Biases.has_value())
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000754 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100755 CompareConstTensor(biases.value(), m_Biases.value());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000756 }
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000757 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000758
759 private:
760 void VerifyDescriptor(const armnn::DepthwiseConvolution2dDescriptor& descriptor)
761 {
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100762 BOOST_CHECK(descriptor.m_PadLeft == m_Descriptor.m_PadLeft);
763 BOOST_CHECK(descriptor.m_PadRight == m_Descriptor.m_PadRight);
764 BOOST_CHECK(descriptor.m_PadTop == m_Descriptor.m_PadTop);
765 BOOST_CHECK(descriptor.m_PadBottom == m_Descriptor.m_PadBottom);
766 BOOST_CHECK(descriptor.m_StrideX == m_Descriptor.m_StrideX);
767 BOOST_CHECK(descriptor.m_StrideY == m_Descriptor.m_StrideY);
768 BOOST_CHECK(descriptor.m_DilationX == m_Descriptor.m_DilationX);
769 BOOST_CHECK(descriptor.m_DilationY == m_Descriptor.m_DilationY);
770 BOOST_CHECK(descriptor.m_BiasEnabled == m_Descriptor.m_BiasEnabled);
771 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000772 }
773
774 armnn::DepthwiseConvolution2dDescriptor m_Descriptor;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100775 armnn::ConstTensor m_Weights;
776 armnn::Optional<armnn::ConstTensor> m_Biases;
Éanna Ó Catháin633f8592019-02-25 16:26:29 +0000777 };
778
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000779 const std::string layerName("depwiseConvolution2d");
780 const armnn::TensorInfo inputInfo ({ 1, 5, 5, 3 }, armnn::DataType::Float32);
781 const armnn::TensorInfo outputInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000782
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000783 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
784 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000785
786 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
787 armnn::ConstTensor weights(weightsInfo, weightsData);
788
789 std::vector<int32_t> biasesData = GenerateRandomData<int32_t>(biasesInfo.GetNumElements());
790 armnn::ConstTensor biases(biasesInfo, biasesData);
791
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000792 armnn::DepthwiseConvolution2dDescriptor descriptor;
Aron Virginas-Tar5e1b0cf2019-06-21 14:20:11 +0100793 descriptor.m_PadLeft = 1;
794 descriptor.m_PadRight = 1;
795 descriptor.m_PadTop = 1;
796 descriptor.m_PadBottom = 1;
797 descriptor.m_StrideX = 2;
798 descriptor.m_StrideY = 2;
799 descriptor.m_DilationX = 2;
800 descriptor.m_DilationY = 2;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000801 descriptor.m_BiasEnabled = true;
802 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
803
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000804 armnn::INetworkPtr network = armnn::INetwork::Create();
805 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
806 armnn::IConnectableLayer* const depthwiseConvLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +0100807 network->AddDepthwiseConvolution2dLayer(descriptor,
808 weights,
809 armnn::Optional<armnn::ConstTensor>(biases),
810 layerName.c_str());
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000811 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
812
813 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000814 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000815
816 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000817 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
818
819 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
820 BOOST_CHECK(deserializedNetwork);
821
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000822 DepthwiseConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
823 deserializedNetwork->Accept(verifier);
Jim Flynn18ce3382019-03-08 11:08:30 +0000824}
825
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +0000826BOOST_AUTO_TEST_CASE(SerializeDequantize)
827{
828 class DequantizeLayerVerifier : public LayerVerifierBase
829 {
830 public:
831 DequantizeLayerVerifier(const std::string& layerName,
832 const std::vector<armnn::TensorInfo>& inputInfos,
833 const std::vector<armnn::TensorInfo>& outputInfos)
834 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
835
836 void VisitDequantizeLayer(const armnn::IConnectableLayer* layer, const char* name) override
837 {
838 VerifyNameAndConnections(layer, name);
839 }
840 };
841
842 const std::string layerName("dequantize");
843 const armnn::TensorInfo inputInfo({ 1, 5, 2, 3 }, armnn::DataType::QuantisedAsymm8, 0.5f, 1);
844 const armnn::TensorInfo outputInfo({ 1, 5, 2, 3 }, armnn::DataType::Float32);
845
846 armnn::INetworkPtr network = armnn::INetwork::Create();
847 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
848 armnn::IConnectableLayer* const dequantizeLayer = network->AddDequantizeLayer(layerName.c_str());
849 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
850
851 inputLayer->GetOutputSlot(0).Connect(dequantizeLayer->GetInputSlot(0));
852 dequantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
853
854 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
855 dequantizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
856
857 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
858 BOOST_CHECK(deserializedNetwork);
859
860 DequantizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo});
861 deserializedNetwork->Accept(verifier);
862}
863
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000864BOOST_AUTO_TEST_CASE(SerializeDeserializeDetectionPostProcess)
865{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000866 class DetectionPostProcessLayerVerifier : public LayerVerifierBase
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000867 {
868 public:
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000869 DetectionPostProcessLayerVerifier(const std::string& layerName,
870 const std::vector<armnn::TensorInfo>& inputInfos,
871 const std::vector<armnn::TensorInfo>& outputInfos,
872 const armnn::DetectionPostProcessDescriptor& descriptor,
873 const armnn::ConstTensor& anchors)
874 : LayerVerifierBase(layerName, inputInfos, outputInfos)
875 , m_Descriptor(descriptor)
876 , m_Anchors(anchors) {}
877
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000878 void VisitDetectionPostProcessLayer(const armnn::IConnectableLayer* layer,
879 const armnn::DetectionPostProcessDescriptor& descriptor,
880 const armnn::ConstTensor& anchors,
881 const char* name) override
882 {
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000883 VerifyNameAndConnections(layer, name);
884 VerifyDescriptor(descriptor);
885
886 CompareConstTensor(anchors, m_Anchors);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000887 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000888
889 private:
890 void VerifyDescriptor(const armnn::DetectionPostProcessDescriptor& descriptor)
891 {
892 BOOST_TEST(descriptor.m_UseRegularNms == m_Descriptor.m_UseRegularNms);
893 BOOST_TEST(descriptor.m_MaxDetections == m_Descriptor.m_MaxDetections);
894 BOOST_TEST(descriptor.m_MaxClassesPerDetection == m_Descriptor.m_MaxClassesPerDetection);
895 BOOST_TEST(descriptor.m_DetectionsPerClass == m_Descriptor.m_DetectionsPerClass);
896 BOOST_TEST(descriptor.m_NmsScoreThreshold == m_Descriptor.m_NmsScoreThreshold);
897 BOOST_TEST(descriptor.m_NmsIouThreshold == m_Descriptor.m_NmsIouThreshold);
898 BOOST_TEST(descriptor.m_NumClasses == m_Descriptor.m_NumClasses);
899 BOOST_TEST(descriptor.m_ScaleY == m_Descriptor.m_ScaleY);
900 BOOST_TEST(descriptor.m_ScaleX == m_Descriptor.m_ScaleX);
901 BOOST_TEST(descriptor.m_ScaleH == m_Descriptor.m_ScaleH);
902 BOOST_TEST(descriptor.m_ScaleW == m_Descriptor.m_ScaleW);
903 }
904
905 armnn::DetectionPostProcessDescriptor m_Descriptor;
906 armnn::ConstTensor m_Anchors;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000907 };
908
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000909 const std::string layerName("detectionPostProcess");
910
911 const std::vector<armnn::TensorInfo> inputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000912 armnn::TensorInfo({ 1, 6, 4 }, armnn::DataType::Float32),
913 armnn::TensorInfo({ 1, 6, 3}, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000914 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000915
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000916 const std::vector<armnn::TensorInfo> outputInfos({
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000917 armnn::TensorInfo({ 1, 3, 4 }, armnn::DataType::Float32),
918 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
919 armnn::TensorInfo({ 1, 3 }, armnn::DataType::Float32),
920 armnn::TensorInfo({ 1 }, armnn::DataType::Float32)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000921 });
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000922
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000923 armnn::DetectionPostProcessDescriptor descriptor;
924 descriptor.m_UseRegularNms = true;
925 descriptor.m_MaxDetections = 3;
926 descriptor.m_MaxClassesPerDetection = 1;
927 descriptor.m_DetectionsPerClass =1;
928 descriptor.m_NmsScoreThreshold = 0.0;
929 descriptor.m_NmsIouThreshold = 0.5;
930 descriptor.m_NumClasses = 2;
931 descriptor.m_ScaleY = 10.0;
932 descriptor.m_ScaleX = 10.0;
933 descriptor.m_ScaleH = 5.0;
934 descriptor.m_ScaleW = 5.0;
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000935
936 const armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32);
937 const std::vector<float> anchorsData({
938 0.5f, 0.5f, 1.0f, 1.0f,
939 0.5f, 0.5f, 1.0f, 1.0f,
940 0.5f, 0.5f, 1.0f, 1.0f,
941 0.5f, 10.5f, 1.0f, 1.0f,
942 0.5f, 10.5f, 1.0f, 1.0f,
943 0.5f, 100.5f, 1.0f, 1.0f
944 });
945 armnn::ConstTensor anchors(anchorsInfo, anchorsData);
946
947 armnn::INetworkPtr network = armnn::INetwork::Create();
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000948 armnn::IConnectableLayer* const detectionLayer =
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000949 network->AddDetectionPostProcessLayer(descriptor, anchors, layerName.c_str());
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000950
951 for (unsigned int i = 0; i < 2; i++)
952 {
953 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(static_cast<int>(i));
954 inputLayer->GetOutputSlot(0).Connect(detectionLayer->GetInputSlot(i));
955 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfos[i]);
956 }
957
958 for (unsigned int i = 0; i < 4; i++)
959 {
960 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(static_cast<int>(i));
961 detectionLayer->GetOutputSlot(i).Connect(outputLayer->GetInputSlot(0));
962 detectionLayer->GetOutputSlot(i).SetTensorInfo(outputInfos[i]);
963 }
964
965 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
966 BOOST_CHECK(deserializedNetwork);
967
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000968 DetectionPostProcessLayerVerifier verifier(layerName, inputInfos, outputInfos, descriptor, anchors);
969 deserializedNetwork->Accept(verifier);
970}
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +0000971
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +0000972BOOST_AUTO_TEST_CASE(SerializeDivision)
973{
974 class DivisionLayerVerifier : public LayerVerifierBase
975 {
976 public:
977 DivisionLayerVerifier(const std::string& layerName,
978 const std::vector<armnn::TensorInfo>& inputInfos,
979 const std::vector<armnn::TensorInfo>& outputInfos)
980 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
981
982 void VisitDivisionLayer(const armnn::IConnectableLayer* layer, const char* name) override
983 {
984 VerifyNameAndConnections(layer, name);
985 }
986 };
987
988 const std::string layerName("division");
989 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
990
991 armnn::INetworkPtr network = armnn::INetwork::Create();
992 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
993 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
994 armnn::IConnectableLayer* const divisionLayer = network->AddDivisionLayer(layerName.c_str());
995 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
996
997 inputLayer0->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(0));
998 inputLayer1->GetOutputSlot(0).Connect(divisionLayer->GetInputSlot(1));
999 divisionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1000
1001 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1002 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1003 divisionLayer->GetOutputSlot(0).SetTensorInfo(info);
1004
1005 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1006 BOOST_CHECK(deserializedNetwork);
1007
1008 DivisionLayerVerifier verifier(layerName, {info, info}, {info});
1009 deserializedNetwork->Accept(verifier);
1010}
1011
1012BOOST_AUTO_TEST_CASE(SerializeEqual)
1013{
1014 class EqualLayerVerifier : public LayerVerifierBase
1015 {
1016 public:
1017 EqualLayerVerifier(const std::string& layerName,
1018 const std::vector<armnn::TensorInfo>& inputInfos,
1019 const std::vector<armnn::TensorInfo>& outputInfos)
1020 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1021
1022 void VisitEqualLayer(const armnn::IConnectableLayer* layer, const char* name) override
1023 {
1024 VerifyNameAndConnections(layer, name);
1025 }
1026 };
1027
1028 const std::string layerName("equal");
1029 const armnn::TensorInfo inputTensorInfo1 = armnn::TensorInfo({2, 1, 2, 4}, armnn::DataType::Float32);
1030 const armnn::TensorInfo inputTensorInfo2 = armnn::TensorInfo({2, 1, 2, 4}, armnn::DataType::Float32);
1031 const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({2, 1, 2, 4}, armnn::DataType::Boolean);
1032
1033 armnn::INetworkPtr network = armnn::INetwork::Create();
1034 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
1035 armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
1036 armnn::IConnectableLayer* const equalLayer = network->AddEqualLayer(layerName.c_str());
1037 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1038
1039 inputLayer1->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(0));
1040 inputLayer2->GetOutputSlot(0).Connect(equalLayer->GetInputSlot(1));
1041 equalLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1042
1043 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo1);
1044 inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo2);
1045 equalLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1046
1047 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1048 BOOST_CHECK(deserializedNetwork);
1049
1050 EqualLayerVerifier verifier(layerName, {inputTensorInfo1, inputTensorInfo2}, {outputTensorInfo});
1051 deserializedNetwork->Accept(verifier);
1052}
1053
1054BOOST_AUTO_TEST_CASE(SerializeFloor)
1055{
1056 class FloorLayerVerifier : public LayerVerifierBase
1057 {
1058 public:
1059 FloorLayerVerifier(const std::string& layerName,
1060 const std::vector<armnn::TensorInfo>& inputInfos,
1061 const std::vector<armnn::TensorInfo>& outputInfos)
1062 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1063
1064 void VisitFloorLayer(const armnn::IConnectableLayer* layer, const char* name) override
1065 {
1066 VerifyNameAndConnections(layer, name);
1067 }
1068 };
1069
1070 const std::string layerName("floor");
1071 const armnn::TensorInfo info({4,4}, armnn::DataType::Float32);
1072
1073 armnn::INetworkPtr network = armnn::INetwork::Create();
1074 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1075 armnn::IConnectableLayer* const floorLayer = network->AddFloorLayer(layerName.c_str());
1076 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1077
1078 inputLayer->GetOutputSlot(0).Connect(floorLayer->GetInputSlot(0));
1079 floorLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1080
1081 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1082 floorLayer->GetOutputSlot(0).SetTensorInfo(info);
1083
1084 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1085 BOOST_CHECK(deserializedNetwork);
1086
1087 FloorLayerVerifier verifier(layerName, {info}, {info});
1088 deserializedNetwork->Accept(verifier);
1089}
1090
1091BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
1092{
1093 class FullyConnectedLayerVerifier : public LayerVerifierBase
1094 {
1095 public:
1096 FullyConnectedLayerVerifier(const std::string& layerName,
1097 const std::vector<armnn::TensorInfo>& inputInfos,
1098 const std::vector<armnn::TensorInfo>& outputInfos,
1099 const armnn::FullyConnectedDescriptor& descriptor,
1100 const armnn::ConstTensor& weight,
1101 const armnn::Optional<armnn::ConstTensor>& bias)
1102 : LayerVerifierBase(layerName, inputInfos, outputInfos)
1103 , m_Descriptor(descriptor)
1104 , m_Weight(weight)
1105 , m_Bias(bias) {}
1106
1107 void VisitFullyConnectedLayer(const armnn::IConnectableLayer* layer,
1108 const armnn::FullyConnectedDescriptor& descriptor,
1109 const armnn::ConstTensor& weight,
1110 const armnn::Optional<armnn::ConstTensor>& bias,
1111 const char* name) override
1112 {
1113 VerifyNameAndConnections(layer, name);
1114 VerifyDescriptor(descriptor);
1115
1116 CompareConstTensor(weight, m_Weight);
1117
1118 BOOST_TEST(bias.has_value() == m_Bias.has_value());
1119 if (bias.has_value() && m_Bias.has_value())
1120 {
1121 CompareConstTensor(bias.value(), m_Bias.value());
1122 }
1123 }
1124
1125 private:
1126 void VerifyDescriptor(const armnn::FullyConnectedDescriptor& descriptor)
1127 {
1128 BOOST_TEST(descriptor.m_BiasEnabled == m_Descriptor.m_BiasEnabled);
1129 BOOST_TEST(descriptor.m_TransposeWeightMatrix == m_Descriptor.m_TransposeWeightMatrix);
1130 }
1131
1132 armnn::FullyConnectedDescriptor m_Descriptor;
1133 armnn::ConstTensor m_Weight;
1134 armnn::Optional<armnn::ConstTensor> m_Bias;
1135 };
1136
1137 const std::string layerName("fullyConnected");
1138 const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
1139 const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
1140
1141 const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
1142 const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
1143 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
1144 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
1145 armnn::ConstTensor weights(weightsInfo, weightsData);
1146 armnn::ConstTensor biases(biasesInfo, biasesData);
1147
1148 armnn::FullyConnectedDescriptor descriptor;
1149 descriptor.m_BiasEnabled = true;
1150 descriptor.m_TransposeWeightMatrix = false;
1151
1152 armnn::INetworkPtr network = armnn::INetwork::Create();
1153 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1154 armnn::IConnectableLayer* const fullyConnectedLayer =
Matteo Martincighfc598e12019-05-14 10:36:13 +01001155 network->AddFullyConnectedLayer(descriptor,
1156 weights,
1157 armnn::Optional<armnn::ConstTensor>(biases),
1158 layerName.c_str());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001159 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1160
1161 inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
1162 fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1163
1164 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1165 fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1166
1167 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1168 BOOST_CHECK(deserializedNetwork);
1169
1170 FullyConnectedLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
1171 deserializedNetwork->Accept(verifier);
1172}
1173
1174BOOST_AUTO_TEST_CASE(SerializeGather)
1175{
1176 class GatherLayerVerifier : public LayerVerifierBase
1177 {
1178 public:
1179 GatherLayerVerifier(const std::string& layerName,
1180 const std::vector<armnn::TensorInfo>& inputInfos,
1181 const std::vector<armnn::TensorInfo>& outputInfos)
1182 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1183
1184 void VisitGatherLayer(const armnn::IConnectableLayer* layer, const char *name) override
1185 {
1186 VerifyNameAndConnections(layer, name);
1187 }
1188
1189 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
1190 const armnn::ConstTensor& input,
1191 const char *name) override {}
1192 };
1193
1194 const std::string layerName("gather");
1195 armnn::TensorInfo paramsInfo({ 8 }, armnn::DataType::QuantisedAsymm8);
1196 armnn::TensorInfo outputInfo({ 3 }, armnn::DataType::QuantisedAsymm8);
1197 const armnn::TensorInfo indicesInfo({ 3 }, armnn::DataType::Signed32);
1198
1199 paramsInfo.SetQuantizationScale(1.0f);
1200 paramsInfo.SetQuantizationOffset(0);
1201 outputInfo.SetQuantizationScale(1.0f);
1202 outputInfo.SetQuantizationOffset(0);
1203
1204 const std::vector<int32_t>& indicesData = {7, 6, 5};
1205
1206 armnn::INetworkPtr network = armnn::INetwork::Create();
1207 armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
1208 armnn::IConnectableLayer *const constantLayer =
1209 network->AddConstantLayer(armnn::ConstTensor(indicesInfo, indicesData));
1210 armnn::IConnectableLayer *const gatherLayer = network->AddGatherLayer(layerName.c_str());
1211 armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
1212
1213 inputLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(0));
1214 constantLayer->GetOutputSlot(0).Connect(gatherLayer->GetInputSlot(1));
1215 gatherLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1216
1217 inputLayer->GetOutputSlot(0).SetTensorInfo(paramsInfo);
1218 constantLayer->GetOutputSlot(0).SetTensorInfo(indicesInfo);
1219 gatherLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1220
1221 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1222 BOOST_CHECK(deserializedNetwork);
1223
1224 GatherLayerVerifier verifier(layerName, {paramsInfo, indicesInfo}, {outputInfo});
1225 deserializedNetwork->Accept(verifier);
1226}
1227
1228BOOST_AUTO_TEST_CASE(SerializeGreater)
1229{
1230 class GreaterLayerVerifier : public LayerVerifierBase
1231 {
1232 public:
1233 GreaterLayerVerifier(const std::string& layerName,
1234 const std::vector<armnn::TensorInfo>& inputInfos,
1235 const std::vector<armnn::TensorInfo>& outputInfos)
1236 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1237
1238 void VisitGreaterLayer(const armnn::IConnectableLayer* layer, const char* name) override
1239 {
1240 VerifyNameAndConnections(layer, name);
1241 }
1242 };
1243
1244 const std::string layerName("greater");
1245 const armnn::TensorInfo inputTensorInfo1({ 1, 2, 2, 2 }, armnn::DataType::Float32);
1246 const armnn::TensorInfo inputTensorInfo2({ 1, 2, 2, 2 }, armnn::DataType::Float32);
1247 const armnn::TensorInfo outputTensorInfo({ 1, 2, 2, 2 }, armnn::DataType::Boolean);
1248
1249 armnn::INetworkPtr network = armnn::INetwork::Create();
1250 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
1251 armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
1252 armnn::IConnectableLayer* const greaterLayer = network->AddGreaterLayer(layerName.c_str());
1253 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1254
1255 inputLayer1->GetOutputSlot(0).Connect(greaterLayer->GetInputSlot(0));
1256 inputLayer2->GetOutputSlot(0).Connect(greaterLayer->GetInputSlot(1));
1257 greaterLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1258
1259 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo1);
1260 inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo2);
1261 greaterLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1262
1263 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1264 BOOST_CHECK(deserializedNetwork);
1265
1266 GreaterLayerVerifier verifier(layerName, {inputTensorInfo1, inputTensorInfo2}, {outputTensorInfo});
1267 deserializedNetwork->Accept(verifier);
1268}
1269
Aron Virginas-Tar781ced92019-10-03 11:15:39 +01001270BOOST_AUTO_TEST_CASE(SerializeInstanceNormalization)
1271{
1272 class InstanceNormalizationLayerVerifier : public LayerVerifierBase
1273 {
1274 public:
1275 InstanceNormalizationLayerVerifier(const std::string& layerName,
1276 const std::vector<armnn::TensorInfo>& inputInfos,
1277 const std::vector<armnn::TensorInfo>& outputInfos,
1278 const armnn::InstanceNormalizationDescriptor& descriptor)
1279 : LayerVerifierBase(layerName, inputInfos, outputInfos)
1280 , m_Descriptor(descriptor) {}
1281
1282 void VisitInstanceNormalizationLayer(const armnn::IConnectableLayer* layer,
1283 const armnn::InstanceNormalizationDescriptor& descriptor,
1284 const char* name) override
1285 {
1286 VerifyNameAndConnections(layer, name);
1287 VerifyDescriptor(descriptor);
1288 }
1289
1290 private:
1291 void VerifyDescriptor(const armnn::InstanceNormalizationDescriptor& descriptor)
1292 {
1293 BOOST_CHECK(descriptor.m_Gamma == m_Descriptor.m_Gamma);
1294 BOOST_CHECK(descriptor.m_Beta == m_Descriptor.m_Beta);
1295 BOOST_CHECK(descriptor.m_Eps == m_Descriptor.m_Eps);
1296 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
1297 }
1298
1299 armnn::InstanceNormalizationDescriptor m_Descriptor;
1300 };
1301
1302 const std::string layerName("instanceNormalization");
1303 const armnn::TensorInfo info({ 1, 2, 1, 5 }, armnn::DataType::Float32);
1304
1305 armnn::InstanceNormalizationDescriptor descriptor;
1306 descriptor.m_Gamma = 1.1f;
1307 descriptor.m_Beta = 0.1f;
1308 descriptor.m_Eps = 0.0001f;
1309 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
1310
1311 armnn::INetworkPtr network = armnn::INetwork::Create();
1312 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1313 armnn::IConnectableLayer* const instanceNormLayer =
1314 network->AddInstanceNormalizationLayer(descriptor, layerName.c_str());
1315 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1316
1317 inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1318 instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1319
1320 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1321 instanceNormLayer->GetOutputSlot(0).SetTensorInfo(info);
1322
1323 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1324 BOOST_CHECK(deserializedNetwork);
1325
1326 InstanceNormalizationLayerVerifier verifier(layerName, {info}, {info}, descriptor);
1327 deserializedNetwork->Accept(verifier);
1328}
1329
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001330class L2NormalizationLayerVerifier : public LayerVerifierBase
1331{
1332public:
1333 L2NormalizationLayerVerifier(const std::string& layerName,
1334 const std::vector<armnn::TensorInfo>& inputInfos,
1335 const std::vector<armnn::TensorInfo>& outputInfos,
1336 const armnn::L2NormalizationDescriptor& descriptor)
1337 : LayerVerifierBase(layerName, inputInfos, outputInfos)
1338 , m_Descriptor(descriptor) {}
1339
1340 void VisitL2NormalizationLayer(const armnn::IConnectableLayer* layer,
1341 const armnn::L2NormalizationDescriptor& descriptor,
1342 const char* name) override
1343 {
1344 VerifyNameAndConnections(layer, name);
1345 VerifyDescriptor(descriptor);
1346 }
1347private:
1348 void VerifyDescriptor(const armnn::L2NormalizationDescriptor& descriptor)
1349 {
1350 BOOST_TEST(descriptor.m_Eps == m_Descriptor.m_Eps);
1351 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
1352 }
1353
1354 armnn::L2NormalizationDescriptor m_Descriptor;
1355};
1356
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001357BOOST_AUTO_TEST_CASE(SerializeL2Normalization)
1358{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001359 const std::string l2NormLayerName("l2Normalization");
1360 const armnn::TensorInfo info({1, 2, 1, 5}, armnn::DataType::Float32);
1361
1362 armnn::L2NormalizationDescriptor desc;
1363 desc.m_DataLayout = armnn::DataLayout::NCHW;
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001364 desc.m_Eps = 0.0001f;
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001365
1366 armnn::INetworkPtr network = armnn::INetwork::Create();
1367 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1368 armnn::IConnectableLayer* const l2NormLayer = network->AddL2NormalizationLayer(desc, l2NormLayerName.c_str());
1369 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1370
1371 inputLayer0->GetOutputSlot(0).Connect(l2NormLayer->GetInputSlot(0));
1372 l2NormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1373
1374 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1375 l2NormLayer->GetOutputSlot(0).SetTensorInfo(info);
1376
1377 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1378 BOOST_CHECK(deserializedNetwork);
1379
1380 L2NormalizationLayerVerifier verifier(l2NormLayerName, {info}, {info}, desc);
1381 deserializedNetwork->Accept(verifier);
1382}
1383
Ferran Balaguer0dcffec2019-06-18 16:25:06 +01001384BOOST_AUTO_TEST_CASE(EnsureL2NormalizationBackwardCompatibility)
1385{
1386 // The hex array below is a flat buffer containing a simple network with one input
1387 // a L2Normalization layer and an output layer with dimensions as per the tensor infos below.
1388 //
1389 // This test verifies that we can still read back these old style
1390 // models without the normalization epsilon value.
1391 unsigned int size = 508;
1392 const unsigned char l2NormalizationModel[] = {
1393 0x10,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x10,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,
1394 0x0C,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3C,0x01,0x00,0x00,
1395 0x74,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
1396 0x02,0x00,0x00,0x00,0xE8,0xFE,0xFF,0xFF,0x00,0x00,0x00,0x0B,0x04,0x00,0x00,0x00,0xD6,0xFE,0xFF,0xFF,
1397 0x0C,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x08,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
1398 0x9E,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
1399 0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
1400 0x00,0x00,0x00,0x00,0x4C,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0xFF,0xFF,0xFF,
1401 0x00,0x00,0x00,0x20,0x0C,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,
1402 0x20,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x06,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,
1403 0x18,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x10,0x00,0x14,0x00,0x0E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
1404 0x10,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,
1405 0x6C,0x32,0x4E,0x6F,0x72,0x6D,0x61,0x6C,0x69,0x7A,0x61,0x74,0x69,0x6F,0x6E,0x00,0x01,0x00,0x00,0x00,
1406 0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x04,0x00,
1407 0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x52,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,
1408 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
1409 0x05,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1410 0x00,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x09,
1411 0x04,0x00,0x00,0x00,0xF6,0xFF,0xFF,0xFF,0x0C,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0A,0x00,0x04,0x00,
1412 0x06,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x14,0x00,0x00,0x00,0x04,0x00,0x08,0x00,
1413 0x0C,0x00,0x10,0x00,0x0E,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
1414 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
1415 0x0C,0x00,0x00,0x00,0x08,0x00,0x0A,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
1416 0x00,0x00,0x0A,0x00,0x10,0x00,0x08,0x00,0x07,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
1417 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
1418 0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0 };
1419
1420 std::stringstream ss;
1421 for (unsigned int i = 0; i < size; ++i)
1422 {
1423 ss << l2NormalizationModel[i];
1424 }
1425 std::string l2NormalizationLayerNetwork = ss.str();
1426 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(l2NormalizationLayerNetwork);
1427 BOOST_CHECK(deserializedNetwork);
1428 const std::string layerName("l2Normalization");
1429 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 2, 1, 5}, armnn::DataType::Float32);
1430
1431 armnn::L2NormalizationDescriptor desc;
1432 desc.m_DataLayout = armnn::DataLayout::NCHW;
1433 // Since this variable does not exist in the l2NormalizationModel[] dump, the default value will be loaded.
1434 desc.m_Eps = 1e-12f;
1435
1436 L2NormalizationLayerVerifier verifier(layerName, {inputInfo}, {inputInfo}, desc);
1437 deserializedNetwork->Accept(verifier);
1438}
1439
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001440BOOST_AUTO_TEST_CASE(SerializeMaximum)
1441{
1442 class MaximumLayerVerifier : public LayerVerifierBase
1443 {
1444 public:
1445 MaximumLayerVerifier(const std::string& layerName,
1446 const std::vector<armnn::TensorInfo>& inputInfos,
1447 const std::vector<armnn::TensorInfo>& outputInfos)
1448 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1449
1450 void VisitMaximumLayer(const armnn::IConnectableLayer* layer, const char* name) override
1451 {
1452 VerifyNameAndConnections(layer, name);
1453 }
1454 };
1455
1456 const std::string layerName("maximum");
1457 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1458
1459 armnn::INetworkPtr network = armnn::INetwork::Create();
1460 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1461 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1462 armnn::IConnectableLayer* const maximumLayer = network->AddMaximumLayer(layerName.c_str());
1463 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1464
1465 inputLayer0->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(0));
1466 inputLayer1->GetOutputSlot(0).Connect(maximumLayer->GetInputSlot(1));
1467 maximumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1468
1469 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1470 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1471 maximumLayer->GetOutputSlot(0).SetTensorInfo(info);
1472
1473 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1474 BOOST_CHECK(deserializedNetwork);
1475
1476 MaximumLayerVerifier verifier(layerName, {info, info}, {info});
1477 deserializedNetwork->Accept(verifier);
1478}
1479
1480BOOST_AUTO_TEST_CASE(SerializeMean)
1481{
1482 class MeanLayerVerifier : public LayerVerifierBase
1483 {
1484 public:
1485 MeanLayerVerifier(const std::string& layerName,
1486 const std::vector<armnn::TensorInfo>& inputInfos,
1487 const std::vector<armnn::TensorInfo>& outputInfos,
1488 const armnn::MeanDescriptor& descriptor)
1489 : LayerVerifierBase(layerName, inputInfos, outputInfos)
1490 , m_Descriptor(descriptor) {}
1491
1492 void VisitMeanLayer(const armnn::IConnectableLayer* layer,
1493 const armnn::MeanDescriptor& descriptor,
1494 const char* name) override
1495 {
1496 VerifyNameAndConnections(layer, name);
1497 VerifyDescriptor(descriptor);
1498 }
1499
1500 private:
1501 void VerifyDescriptor(const armnn::MeanDescriptor& descriptor)
1502 {
1503 BOOST_TEST(descriptor.m_Axis == m_Descriptor.m_Axis);
1504 BOOST_TEST(descriptor.m_KeepDims == m_Descriptor.m_KeepDims);
1505 }
1506
1507 armnn::MeanDescriptor m_Descriptor;
1508 };
1509
1510 const std::string layerName("mean");
1511 const armnn::TensorInfo inputInfo({1, 1, 3, 2}, armnn::DataType::Float32);
1512 const armnn::TensorInfo outputInfo({1, 1, 1, 2}, armnn::DataType::Float32);
1513
1514 armnn::MeanDescriptor descriptor;
1515 descriptor.m_Axis = { 2 };
1516 descriptor.m_KeepDims = true;
1517
1518 armnn::INetworkPtr network = armnn::INetwork::Create();
1519 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1520 armnn::IConnectableLayer* const meanLayer = network->AddMeanLayer(descriptor, layerName.c_str());
1521 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1522
1523 inputLayer->GetOutputSlot(0).Connect(meanLayer->GetInputSlot(0));
1524 meanLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1525
1526 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
1527 meanLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1528
1529 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1530 BOOST_CHECK(deserializedNetwork);
1531
1532 MeanLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
1533 deserializedNetwork->Accept(verifier);
1534}
1535
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001536BOOST_AUTO_TEST_CASE(SerializeMerge)
1537{
1538 class MergeLayerVerifier : public LayerVerifierBase
1539 {
1540 public:
1541 MergeLayerVerifier(const std::string& layerName,
1542 const std::vector<armnn::TensorInfo>& inputInfos,
1543 const std::vector<armnn::TensorInfo>& outputInfos)
1544 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1545
1546 void VisitMergeLayer(const armnn::IConnectableLayer* layer, const char* name) override
1547 {
1548 VerifyNameAndConnections(layer, name);
1549 }
1550 };
1551
1552 const std::string layerName("merge");
1553 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1554
1555 armnn::INetworkPtr network = armnn::INetwork::Create();
1556 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1557 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1558 armnn::IConnectableLayer* const mergeLayer = network->AddMergeLayer(layerName.c_str());
1559 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1560
1561 inputLayer0->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(0));
1562 inputLayer1->GetOutputSlot(0).Connect(mergeLayer->GetInputSlot(1));
1563 mergeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1564
1565 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1566 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1567 mergeLayer->GetOutputSlot(0).SetTensorInfo(info);
1568
1569 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1570 BOOST_CHECK(deserializedNetwork);
1571
1572 MergeLayerVerifier verifier(layerName, {info, info}, {info});
1573 deserializedNetwork->Accept(verifier);
1574}
1575
Jim Flynn5fa83932019-05-09 15:35:43 +01001576class MergerLayerVerifier : public LayerVerifierBase
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001577{
Jim Flynn5fa83932019-05-09 15:35:43 +01001578public:
1579 MergerLayerVerifier(const std::string& layerName,
1580 const std::vector<armnn::TensorInfo>& inputInfos,
1581 const std::vector<armnn::TensorInfo>& outputInfos,
1582 const armnn::OriginsDescriptor& descriptor)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001583 : LayerVerifierBase(layerName, inputInfos, outputInfos)
1584 , m_Descriptor(descriptor) {}
1585
Jim Flynn5fa83932019-05-09 15:35:43 +01001586 void VisitMergerLayer(const armnn::IConnectableLayer* layer,
1587 const armnn::OriginsDescriptor& descriptor,
1588 const char* name) override
1589 {
Jim Flynne242f2d2019-05-22 14:24:13 +01001590 throw armnn::Exception("MergerLayer should have translated to ConcatLayer");
1591 }
1592
1593 void VisitConcatLayer(const armnn::IConnectableLayer* layer,
1594 const armnn::OriginsDescriptor& descriptor,
1595 const char* name) override
1596 {
Jim Flynn5fa83932019-05-09 15:35:43 +01001597 VerifyNameAndConnections(layer, name);
1598 VerifyDescriptor(descriptor);
1599 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001600
Jim Flynn5fa83932019-05-09 15:35:43 +01001601private:
1602 void VerifyDescriptor(const armnn::OriginsDescriptor& descriptor)
1603 {
1604 BOOST_TEST(descriptor.GetConcatAxis() == m_Descriptor.GetConcatAxis());
1605 BOOST_TEST(descriptor.GetNumViews() == m_Descriptor.GetNumViews());
1606 BOOST_TEST(descriptor.GetNumDimensions() == m_Descriptor.GetNumDimensions());
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001607
Jim Flynn5fa83932019-05-09 15:35:43 +01001608 for (uint32_t i = 0; i < descriptor.GetNumViews(); i++)
1609 {
1610 for (uint32_t j = 0; j < descriptor.GetNumDimensions(); j++)
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001611 {
Jim Flynn5fa83932019-05-09 15:35:43 +01001612 BOOST_TEST(descriptor.GetViewOrigin(i)[j] == m_Descriptor.GetViewOrigin(i)[j]);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001613 }
1614 }
Jim Flynn5fa83932019-05-09 15:35:43 +01001615 }
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001616
Jim Flynn5fa83932019-05-09 15:35:43 +01001617 armnn::OriginsDescriptor m_Descriptor;
1618};
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001619
Jim Flynne242f2d2019-05-22 14:24:13 +01001620// NOTE: until the deprecated AddMergerLayer disappears this test checks that calling
1621// AddMergerLayer places a ConcatLayer into the serialized format and that
1622// when this deserialises we have a ConcatLayer
Jim Flynn5fa83932019-05-09 15:35:43 +01001623BOOST_AUTO_TEST_CASE(SerializeMerger)
1624{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001625 const std::string layerName("merger");
1626 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1627 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1628
1629 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1630
1631 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001632 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001633
1634 armnn::INetworkPtr network = armnn::INetwork::Create();
1635 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1636 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
Jim Flynn906f9462019-05-10 13:55:21 +01001637 ARMNN_NO_DEPRECATE_WARN_BEGIN
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001638 armnn::IConnectableLayer* const mergerLayer = network->AddMergerLayer(descriptor, layerName.c_str());
Jim Flynn906f9462019-05-10 13:55:21 +01001639 ARMNN_NO_DEPRECATE_WARN_END
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001640 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1641
1642 inputLayerOne->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0));
1643 inputLayerTwo->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1));
1644 mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1645
1646 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1647 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1648 mergerLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1649
Jim Flynn5fa83932019-05-09 15:35:43 +01001650 std::string mergerLayerNetwork = SerializeNetwork(*network);
1651 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(mergerLayerNetwork);
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001652 BOOST_CHECK(deserializedNetwork);
1653
1654 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1655 deserializedNetwork->Accept(verifier);
1656}
1657
Jim Flynn5fa83932019-05-09 15:35:43 +01001658BOOST_AUTO_TEST_CASE(EnsureMergerLayerBackwardCompatibility)
1659{
1660 // The hex array below is a flat buffer containing a simple network with two inputs
Jim Flynne242f2d2019-05-22 14:24:13 +01001661 // a merger layer (now deprecated) and an output layer with dimensions as per the tensor infos below.
1662 //
1663 // This test verifies that we can still read back these old style
Jim Flynn5fa83932019-05-09 15:35:43 +01001664 // models replacing the MergerLayers with ConcatLayers with the same parameters.
Jim Flynn5fa83932019-05-09 15:35:43 +01001665 unsigned int size = 760;
1666 const unsigned char mergerModel[] = {
1667 0x10,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x10,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,
1668 0x0C,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x38,0x02,0x00,0x00,
1669 0x8C,0x01,0x00,0x00,0x70,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1670 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xF4,0xFD,0xFF,0xFF,0x00,0x00,0x00,0x0B,
1671 0x04,0x00,0x00,0x00,0x92,0xFE,0xFF,0xFF,0x04,0x00,0x00,0x00,0x9A,0xFE,0xFF,0xFF,0x04,0x00,0x00,0x00,
1672 0x7E,0xFE,0xFF,0xFF,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
1673 0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
1674 0x00,0x00,0x00,0x00,0xF8,0xFE,0xFF,0xFF,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0xFE,0xFF,0xFF,
1675 0x00,0x00,0x00,0x1F,0x0C,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,
1676 0x68,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x0C,0x00,0x10,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,
1677 0x0C,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
1678 0x24,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x22,0xFF,0xFF,0xFF,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
1679 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0xFF,0xFF,0xFF,
1680 0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1681 0x00,0x00,0x00,0x00,0x36,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,
1682 0x14,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x6D,0x65,0x72,0x67,0x65,0x72,0x00,0x00,
1683 0x02,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
1684 0x34,0xFF,0xFF,0xFF,0x04,0x00,0x00,0x00,0x92,0xFE,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,
1685 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
1686 0x02,0x00,0x00,0x00,0x08,0x00,0x10,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
1687 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,
1688 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0E,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x00,0x00,
1689 0x00,0x00,0x00,0x09,0x0C,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x08,0x00,0x04,0x00,0x06,0x00,0x00,0x00,
1690 0x0C,0x00,0x00,0x00,0x08,0x00,0x0E,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,
1691 0x01,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x18,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x10,0x00,0x14,0x00,
1692 0x0E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
1693 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
1694 0x0C,0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
1695 0x66,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
1696 0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,
1697 0x07,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x00,0xF6,0xFF,0xFF,0xFF,
1698 0x0C,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0A,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
1699 0x00,0x00,0x0E,0x00,0x14,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x10,0x00,0x0E,0x00,0x00,0x00,
1700 0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1701 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x08,0x00,0x0A,0x00,
1702 0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x10,0x00,0x08,0x00,
1703 0x07,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1704 0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00};
1705 std::stringstream ss;
1706 for (unsigned int i = 0; i < size; ++i)
1707 {
1708 ss << mergerModel[i];
1709 }
1710 std::string mergerLayerNetwork = ss.str();
1711 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(mergerLayerNetwork);
1712 BOOST_CHECK(deserializedNetwork);
1713 const std::string layerName("merger");
1714 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1715 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1716
1717 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1718
1719 armnn::OriginsDescriptor descriptor =
Jim Flynn825af452019-05-20 12:49:28 +01001720 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
Jim Flynn5fa83932019-05-09 15:35:43 +01001721
1722 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1723 deserializedNetwork->Accept(verifier);
1724}
1725
Jim Flynne242f2d2019-05-22 14:24:13 +01001726BOOST_AUTO_TEST_CASE(SerializeConcat)
1727{
1728 const std::string layerName("concat");
1729 const armnn::TensorInfo inputInfo = armnn::TensorInfo({2, 3, 2, 2}, armnn::DataType::Float32);
1730 const armnn::TensorInfo outputInfo = armnn::TensorInfo({4, 3, 2, 2}, armnn::DataType::Float32);
1731
1732 const std::vector<armnn::TensorShape> shapes({inputInfo.GetShape(), inputInfo.GetShape()});
1733
1734 armnn::OriginsDescriptor descriptor =
1735 armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), 0);
1736
1737 armnn::INetworkPtr network = armnn::INetwork::Create();
1738 armnn::IConnectableLayer* const inputLayerOne = network->AddInputLayer(0);
1739 armnn::IConnectableLayer* const inputLayerTwo = network->AddInputLayer(1);
1740 armnn::IConnectableLayer* const concatLayer = network->AddConcatLayer(descriptor, layerName.c_str());
1741 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1742
1743 inputLayerOne->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
1744 inputLayerTwo->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
1745 concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1746
1747 inputLayerOne->GetOutputSlot(0).SetTensorInfo(inputInfo);
1748 inputLayerTwo->GetOutputSlot(0).SetTensorInfo(inputInfo);
1749 concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1750
1751 std::string concatLayerNetwork = SerializeNetwork(*network);
1752 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(concatLayerNetwork);
1753 BOOST_CHECK(deserializedNetwork);
1754
1755 // NOTE: using the MergerLayerVerifier to ensure that it is a concat layer and not a
1756 // merger layer that gets placed into the graph.
1757 MergerLayerVerifier verifier(layerName, {inputInfo, inputInfo}, {outputInfo}, descriptor);
1758 deserializedNetwork->Accept(verifier);
1759}
1760
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001761BOOST_AUTO_TEST_CASE(SerializeMinimum)
1762{
1763 class MinimumLayerVerifier : public LayerVerifierBase
1764 {
1765 public:
1766 MinimumLayerVerifier(const std::string& layerName,
1767 const std::vector<armnn::TensorInfo>& inputInfos,
1768 const std::vector<armnn::TensorInfo>& outputInfos)
1769 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1770
1771 void VisitMinimumLayer(const armnn::IConnectableLayer* layer, const char* name) override
1772 {
1773 VerifyNameAndConnections(layer, name);
1774 }
1775 };
1776
1777 const std::string layerName("minimum");
1778 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
1779
1780 armnn::INetworkPtr network = armnn::INetwork::Create();
1781 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1782 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1783 armnn::IConnectableLayer* const minimumLayer = network->AddMinimumLayer(layerName.c_str());
1784 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1785
1786 inputLayer0->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(0));
1787 inputLayer1->GetOutputSlot(0).Connect(minimumLayer->GetInputSlot(1));
1788 minimumLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1789
1790 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1791 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1792 minimumLayer->GetOutputSlot(0).SetTensorInfo(info);
1793
1794 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1795 BOOST_CHECK(deserializedNetwork);
1796
1797 MinimumLayerVerifier verifier(layerName, {info, info}, {info});
1798 deserializedNetwork->Accept(verifier);
1799}
1800
1801BOOST_AUTO_TEST_CASE(SerializeMultiplication)
1802{
1803 class MultiplicationLayerVerifier : public LayerVerifierBase
1804 {
1805 public:
1806 MultiplicationLayerVerifier(const std::string& layerName,
1807 const std::vector<armnn::TensorInfo>& inputInfos,
1808 const std::vector<armnn::TensorInfo>& outputInfos)
1809 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1810
1811 void VisitMultiplicationLayer(const armnn::IConnectableLayer* layer, const char* name) override
1812 {
1813 VerifyNameAndConnections(layer, name);
1814 }
1815 };
1816
1817 const std::string layerName("multiplication");
1818 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
1819
1820 armnn::INetworkPtr network = armnn::INetwork::Create();
1821 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
1822 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
1823 armnn::IConnectableLayer* const multiplicationLayer = network->AddMultiplicationLayer(layerName.c_str());
1824 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1825
1826 inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(0));
1827 inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(1));
1828 multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1829
1830 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
1831 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
1832 multiplicationLayer->GetOutputSlot(0).SetTensorInfo(info);
1833
1834 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1835 BOOST_CHECK(deserializedNetwork);
1836
1837 MultiplicationLayerVerifier verifier(layerName, {info, info}, {info});
1838 deserializedNetwork->Accept(verifier);
1839}
1840
Ellen Norris-Thompson51982472019-06-19 11:46:21 +01001841BOOST_AUTO_TEST_CASE(SerializePrelu)
1842{
1843 class PreluLayerVerifier : public LayerVerifierBase
1844 {
1845 public:
1846 PreluLayerVerifier(const std::string& layerName,
1847 const std::vector<armnn::TensorInfo>& inputInfos,
1848 const std::vector<armnn::TensorInfo>& outputInfos)
1849 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
1850
1851 void VisitPreluLayer(const armnn::IConnectableLayer* layer, const char* name) override
1852 {
1853 VerifyNameAndConnections(layer, name);
1854 }
1855 };
1856
1857 const std::string layerName("prelu");
1858
1859 armnn::TensorInfo inputTensorInfo ({ 4, 1, 2 }, armnn::DataType::Float32);
1860 armnn::TensorInfo alphaTensorInfo ({ 5, 4, 3, 1 }, armnn::DataType::Float32);
1861 armnn::TensorInfo outputTensorInfo({ 5, 4, 3, 2 }, armnn::DataType::Float32);
1862
1863 armnn::INetworkPtr network = armnn::INetwork::Create();
1864 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1865 armnn::IConnectableLayer* const alphaLayer = network->AddInputLayer(1);
1866 armnn::IConnectableLayer* const preluLayer = network->AddPreluLayer(layerName.c_str());
1867 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1868
1869 inputLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(0));
1870 alphaLayer->GetOutputSlot(0).Connect(preluLayer->GetInputSlot(1));
1871 preluLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1872
1873 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
1874 alphaLayer->GetOutputSlot(0).SetTensorInfo(alphaTensorInfo);
1875 preluLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1876
1877 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1878 BOOST_CHECK(deserializedNetwork);
1879
1880 PreluLayerVerifier verifier(layerName, {inputTensorInfo, alphaTensorInfo}, {outputTensorInfo});
1881 deserializedNetwork->Accept(verifier);
1882}
1883
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001884BOOST_AUTO_TEST_CASE(SerializeNormalization)
1885{
1886 class NormalizationLayerVerifier : public LayerVerifierBase
1887 {
1888 public:
1889 NormalizationLayerVerifier(const std::string& layerName,
1890 const std::vector<armnn::TensorInfo>& inputInfos,
1891 const std::vector<armnn::TensorInfo>& outputInfos,
1892 const armnn::NormalizationDescriptor& descriptor)
1893 : LayerVerifierBase(layerName, inputInfos, outputInfos)
1894 , m_Descriptor(descriptor) {}
1895
1896 void VisitNormalizationLayer(const armnn::IConnectableLayer* layer,
1897 const armnn::NormalizationDescriptor& descriptor,
1898 const char* name) override
1899 {
1900 VerifyNameAndConnections(layer, name);
1901 VerifyDescriptor(descriptor);
1902 }
1903
1904 private:
1905 void VerifyDescriptor(const armnn::NormalizationDescriptor& descriptor)
1906 {
1907 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
1908 BOOST_TEST(descriptor.m_NormSize == m_Descriptor.m_NormSize);
1909 BOOST_TEST(descriptor.m_Alpha == m_Descriptor.m_Alpha);
1910 BOOST_TEST(descriptor.m_Beta == m_Descriptor.m_Beta);
1911 BOOST_TEST(descriptor.m_K == m_Descriptor.m_K);
1912 BOOST_TEST(
1913 static_cast<int>(descriptor.m_NormChannelType) == static_cast<int>(m_Descriptor.m_NormChannelType));
1914 BOOST_TEST(
1915 static_cast<int>(descriptor.m_NormMethodType) == static_cast<int>(m_Descriptor.m_NormMethodType));
1916 }
1917
1918 armnn::NormalizationDescriptor m_Descriptor;
1919 };
1920
1921 const std::string layerName("normalization");
1922 const armnn::TensorInfo info({2, 1, 2, 2}, armnn::DataType::Float32);
1923
1924 armnn::NormalizationDescriptor desc;
1925 desc.m_DataLayout = armnn::DataLayout::NCHW;
1926 desc.m_NormSize = 3;
1927 desc.m_Alpha = 1;
1928 desc.m_Beta = 1;
1929 desc.m_K = 1;
1930
1931 armnn::INetworkPtr network = armnn::INetwork::Create();
1932 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1933 armnn::IConnectableLayer* const normalizationLayer = network->AddNormalizationLayer(desc, layerName.c_str());
1934 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1935
1936 inputLayer->GetOutputSlot(0).Connect(normalizationLayer->GetInputSlot(0));
1937 normalizationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1938
1939 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1940 normalizationLayer->GetOutputSlot(0).SetTensorInfo(info);
1941
1942 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1943 BOOST_CHECK(deserializedNetwork);
1944
1945 NormalizationLayerVerifier verifier(layerName, {info}, {info}, desc);
1946 deserializedNetwork->Accept(verifier);
1947}
1948
Jim Flynn965c7c62019-06-24 14:32:41 +01001949class PadLayerVerifier : public LayerVerifierBase
1950{
1951public:
1952 PadLayerVerifier(const std::string& layerName,
1953 const std::vector<armnn::TensorInfo>& inputInfos,
1954 const std::vector<armnn::TensorInfo>& outputInfos,
1955 const armnn::PadDescriptor& descriptor)
1956 : LayerVerifierBase(layerName, inputInfos, outputInfos), m_Descriptor(descriptor) {}
1957
1958 void VisitPadLayer(const armnn::IConnectableLayer* layer,
1959 const armnn::PadDescriptor& descriptor,
1960 const char* name) override
1961 {
1962 VerifyNameAndConnections(layer, name);
1963 VerifyDescriptor(descriptor);
1964 }
1965
1966private:
1967 void VerifyDescriptor(const armnn::PadDescriptor& descriptor)
1968 {
1969 BOOST_TEST(descriptor.m_PadList == m_Descriptor.m_PadList);
Aron Virginas-Tarf3569052019-07-05 16:01:08 +01001970 BOOST_TEST(descriptor.m_PadValue == m_Descriptor.m_PadValue);
Jim Flynn965c7c62019-06-24 14:32:41 +01001971 }
1972
1973 armnn::PadDescriptor m_Descriptor;
1974};
1975
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001976BOOST_AUTO_TEST_CASE(SerializePad)
1977{
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00001978
1979 const std::string layerName("pad");
1980 const armnn::TensorInfo inputTensorInfo = armnn::TensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
1981 const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({1, 3, 5, 7}, armnn::DataType::Float32);
1982
1983 armnn::PadDescriptor desc({{0, 0}, {1, 0}, {1, 1}, {1, 2}});
1984
1985 armnn::INetworkPtr network = armnn::INetwork::Create();
1986 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
1987 armnn::IConnectableLayer* const padLayer = network->AddPadLayer(desc, layerName.c_str());
1988 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
1989
1990 inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
1991 padLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1992
1993 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
1994 padLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1995
1996 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
1997 BOOST_CHECK(deserializedNetwork);
1998
1999 PadLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, desc);
2000 deserializedNetwork->Accept(verifier);
2001}
2002
Jim Flynn965c7c62019-06-24 14:32:41 +01002003BOOST_AUTO_TEST_CASE(CheckSerializePadBackwardCompatibility)
2004{
2005 // The PadDescriptor is being extended with a float PadValue (so a value other than 0
2006 // can be used to pad the tensor.
2007 //
2008 // This test contains a binary representation of a simple input->pad->output network
2009 // prior to this change to test that the descriptor has been updated in a backward
2010 // compatible way with respect to Deserialization of older binary dumps
2011 unsigned int size = 532;
2012 const unsigned char padModel[] = {
2013 0x10,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x10,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,
2014 0x0C,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x54,0x01,0x00,0x00,
2015 0x6C,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
2016 0x02,0x00,0x00,0x00,0xD0,0xFE,0xFF,0xFF,0x00,0x00,0x00,0x0B,0x04,0x00,0x00,0x00,0x96,0xFF,0xFF,0xFF,
2017 0x04,0x00,0x00,0x00,0x9E,0xFF,0xFF,0xFF,0x04,0x00,0x00,0x00,0x72,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,
2018 0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
2019 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2C,0xFF,0xFF,0xFF,
2020 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x16,0x0C,0x00,0x00,0x00,
2021 0x08,0x00,0x0E,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,
2022 0x00,0x00,0x06,0x00,0x08,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
2023 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
2024 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x18,0x00,0x04,0x00,
2025 0x08,0x00,0x0C,0x00,0x10,0x00,0x14,0x00,0x0E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
2026 0x14,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x70,0x61,0x64,0x00,
2027 0x01,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x08,0x00,0x08,0x00,
2028 0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x52,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,
2029 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
2030 0x05,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,
2031 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x00,0x00,
2032 0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x00,0xF6,0xFF,0xFF,0xFF,0x0C,0x00,0x00,0x00,0x00,0x00,0x06,0x00,
2033 0x0A,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x14,0x00,0x00,0x00,
2034 0x04,0x00,0x08,0x00,0x0C,0x00,0x10,0x00,0x0E,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
2035 0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
2036 0x01,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x08,0x00,0x0A,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,
2037 0x10,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x10,0x00,0x08,0x00,0x07,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,
2038 0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
2039 0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0 };
2040
2041 std::stringstream ss;
2042 for (unsigned int i = 0; i < size; ++i)
2043 {
2044 ss << padModel[i];
2045 }
2046 std::string padNetwork = ss.str();
2047 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(padNetwork);
2048 BOOST_CHECK(deserializedNetwork);
2049
2050 const std::string layerName("pad");
2051 const armnn::TensorInfo inputTensorInfo = armnn::TensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2052 const armnn::TensorInfo outputTensorInfo = armnn::TensorInfo({1, 3, 5, 7}, armnn::DataType::Float32);
2053
2054 armnn::PadDescriptor desc({{0, 0}, {1, 0}, {1, 1}, {1, 2}});
2055
2056 PadLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, desc);
2057 deserializedNetwork->Accept(verifier);
2058}
2059
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002060BOOST_AUTO_TEST_CASE(SerializePermute)
2061{
2062 class PermuteLayerVerifier : public LayerVerifierBase
2063 {
2064 public:
2065 PermuteLayerVerifier(const std::string& layerName,
2066 const std::vector<armnn::TensorInfo>& inputInfos,
2067 const std::vector<armnn::TensorInfo>& outputInfos,
2068 const armnn::PermuteDescriptor& descriptor)
2069 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2070 , m_Descriptor(descriptor) {}
2071
2072 void VisitPermuteLayer(const armnn::IConnectableLayer* layer,
2073 const armnn::PermuteDescriptor& descriptor,
2074 const char* name) override
2075 {
2076 VerifyNameAndConnections(layer, name);
2077 VerifyDescriptor(descriptor);
2078 }
2079
2080 private:
2081 void VerifyDescriptor(const armnn::PermuteDescriptor& descriptor)
2082 {
2083 BOOST_TEST(descriptor.m_DimMappings.IsEqual(m_Descriptor.m_DimMappings));
2084 }
2085
2086 armnn::PermuteDescriptor m_Descriptor;
2087 };
2088
2089 const std::string layerName("permute");
2090 const armnn::TensorInfo inputTensorInfo({4, 3, 2, 1}, armnn::DataType::Float32);
2091 const armnn::TensorInfo outputTensorInfo({1, 2, 3, 4}, armnn::DataType::Float32);
2092
2093 armnn::PermuteDescriptor descriptor(armnn::PermutationVector({3, 2, 1, 0}));
2094
2095 armnn::INetworkPtr network = armnn::INetwork::Create();
2096 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2097 armnn::IConnectableLayer* const permuteLayer = network->AddPermuteLayer(descriptor, layerName.c_str());
2098 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2099
2100 inputLayer->GetOutputSlot(0).Connect(permuteLayer->GetInputSlot(0));
2101 permuteLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2102
2103 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2104 permuteLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2105
2106 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2107 BOOST_CHECK(deserializedNetwork);
2108
2109 PermuteLayerVerifier verifier(layerName, {inputTensorInfo}, {outputTensorInfo}, descriptor);
2110 deserializedNetwork->Accept(verifier);
2111}
2112
2113BOOST_AUTO_TEST_CASE(SerializePooling2d)
2114{
2115 class Pooling2dLayerVerifier : public LayerVerifierBase
2116 {
2117 public:
2118 Pooling2dLayerVerifier(const std::string& layerName,
2119 const std::vector<armnn::TensorInfo>& inputInfos,
2120 const std::vector<armnn::TensorInfo>& outputInfos,
2121 const armnn::Pooling2dDescriptor& descriptor)
2122 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2123 , m_Descriptor(descriptor) {}
2124
2125 void VisitPooling2dLayer(const armnn::IConnectableLayer* layer,
2126 const armnn::Pooling2dDescriptor& descriptor,
2127 const char* name) override
2128 {
2129 VerifyNameAndConnections(layer, name);
2130 VerifyDescriptor(descriptor);
2131 }
2132
2133 private:
2134 void VerifyDescriptor(const armnn::Pooling2dDescriptor& descriptor)
2135 {
2136 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
2137 BOOST_TEST(descriptor.m_PadLeft == m_Descriptor.m_PadLeft);
2138 BOOST_TEST(descriptor.m_PadRight == m_Descriptor.m_PadRight);
2139 BOOST_TEST(descriptor.m_PadTop == m_Descriptor.m_PadTop);
2140 BOOST_TEST(descriptor.m_PadBottom == m_Descriptor.m_PadBottom);
2141 BOOST_TEST(descriptor.m_PoolWidth == m_Descriptor.m_PoolWidth);
2142 BOOST_TEST(descriptor.m_PoolHeight == m_Descriptor.m_PoolHeight);
2143 BOOST_TEST(descriptor.m_StrideX == m_Descriptor.m_StrideX);
2144 BOOST_TEST(descriptor.m_StrideY == m_Descriptor.m_StrideY);
2145
2146 BOOST_TEST(
2147 static_cast<int>(descriptor.m_PaddingMethod) == static_cast<int>(m_Descriptor.m_PaddingMethod));
2148 BOOST_TEST(
2149 static_cast<int>(descriptor.m_PoolType) == static_cast<int>(m_Descriptor.m_PoolType));
2150 BOOST_TEST(
2151 static_cast<int>(descriptor.m_OutputShapeRounding) ==
2152 static_cast<int>(m_Descriptor.m_OutputShapeRounding));
2153 }
2154
2155 armnn::Pooling2dDescriptor m_Descriptor;
2156 };
2157
2158 const std::string layerName("pooling2d");
2159 const armnn::TensorInfo inputInfo({1, 2, 2, 1}, armnn::DataType::Float32);
2160 const armnn::TensorInfo outputInfo({1, 1, 1, 1}, armnn::DataType::Float32);
2161
2162 armnn::Pooling2dDescriptor desc;
2163 desc.m_DataLayout = armnn::DataLayout::NHWC;
2164 desc.m_PadTop = 0;
2165 desc.m_PadBottom = 0;
2166 desc.m_PadLeft = 0;
2167 desc.m_PadRight = 0;
2168 desc.m_PoolType = armnn::PoolingAlgorithm::Average;
2169 desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
2170 desc.m_PaddingMethod = armnn::PaddingMethod::Exclude;
2171 desc.m_PoolHeight = 2;
2172 desc.m_PoolWidth = 2;
2173 desc.m_StrideX = 2;
2174 desc.m_StrideY = 2;
2175
2176 armnn::INetworkPtr network = armnn::INetwork::Create();
2177 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2178 armnn::IConnectableLayer* const pooling2dLayer = network->AddPooling2dLayer(desc, layerName.c_str());
2179 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2180
2181 inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0));
2182 pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2183
2184 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2185 pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2186
2187 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2188 BOOST_CHECK(deserializedNetwork);
2189
2190 Pooling2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2191 deserializedNetwork->Accept(verifier);
2192}
2193
Derek Lamberti87acb272019-03-27 16:51:31 +00002194BOOST_AUTO_TEST_CASE(SerializeQuantize)
2195{
2196 class QuantizeLayerVerifier : public LayerVerifierBase
2197 {
2198 public:
2199 QuantizeLayerVerifier(const std::string& layerName,
2200 const std::vector<armnn::TensorInfo>& inputInfos,
2201 const std::vector<armnn::TensorInfo>& outputInfos)
2202 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2203
2204 void VisitQuantizeLayer(const armnn::IConnectableLayer* layer, const char* name) override
2205 {
2206 VerifyNameAndConnections(layer, name);
2207 }
2208 };
2209
2210 const std::string layerName("quantize");
2211 const armnn::TensorInfo info({ 1, 2, 2, 3 }, armnn::DataType::Float32);
2212
2213 armnn::INetworkPtr network = armnn::INetwork::Create();
2214 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2215 armnn::IConnectableLayer* const quantizeLayer = network->AddQuantizeLayer(layerName.c_str());
2216 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2217
2218 inputLayer->GetOutputSlot(0).Connect(quantizeLayer->GetInputSlot(0));
2219 quantizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2220
2221 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2222 quantizeLayer->GetOutputSlot(0).SetTensorInfo(info);
2223
2224 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2225 BOOST_CHECK(deserializedNetwork);
2226
2227 QuantizeLayerVerifier verifier(layerName, {info}, {info});
2228 deserializedNetwork->Accept(verifier);
2229}
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002230BOOST_AUTO_TEST_CASE(SerializeReshape)
2231{
2232 class ReshapeLayerVerifier : public LayerVerifierBase
2233 {
2234 public:
2235 ReshapeLayerVerifier(const std::string& layerName,
2236 const std::vector<armnn::TensorInfo>& inputInfos,
2237 const std::vector<armnn::TensorInfo>& outputInfos,
2238 const armnn::ReshapeDescriptor& descriptor)
2239 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2240 , m_Descriptor(descriptor) {}
2241
2242 void VisitReshapeLayer(const armnn::IConnectableLayer* layer,
2243 const armnn::ReshapeDescriptor& descriptor,
2244 const char* name) override
2245 {
2246 VerifyNameAndConnections(layer, name);
2247 VerifyDescriptor(descriptor);
2248 }
2249
2250 private:
2251 void VerifyDescriptor(const armnn::ReshapeDescriptor& descriptor)
2252 {
2253 BOOST_TEST(descriptor.m_TargetShape == m_Descriptor.m_TargetShape);
2254 }
2255
2256 armnn::ReshapeDescriptor m_Descriptor;
2257 };
2258
2259 const std::string layerName("reshape");
2260 const armnn::TensorInfo inputInfo({1, 9}, armnn::DataType::Float32);
2261 const armnn::TensorInfo outputInfo({3, 3}, armnn::DataType::Float32);
2262
2263 armnn::ReshapeDescriptor descriptor({3, 3});
2264
2265 armnn::INetworkPtr network = armnn::INetwork::Create();
2266 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2267 armnn::IConnectableLayer* const reshapeLayer = network->AddReshapeLayer(descriptor, layerName.c_str());
2268 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2269
2270 inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0));
2271 reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2272
2273 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2274 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2275
2276 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2277 BOOST_CHECK(deserializedNetwork);
2278
2279 ReshapeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2280 deserializedNetwork->Accept(verifier);
2281}
2282
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002283BOOST_AUTO_TEST_CASE(SerializeResize)
2284{
2285 class ResizeLayerVerifier : public LayerVerifierBase
2286 {
2287 public:
2288 ResizeLayerVerifier(const std::string& layerName,
2289 const std::vector<armnn::TensorInfo>& inputInfos,
2290 const std::vector<armnn::TensorInfo>& outputInfos,
2291 const armnn::ResizeDescriptor& descriptor)
2292 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2293 , m_Descriptor(descriptor) {}
2294
2295 void VisitResizeLayer(const armnn::IConnectableLayer* layer,
2296 const armnn::ResizeDescriptor& descriptor,
2297 const char* name) override
2298 {
2299 VerifyNameAndConnections(layer, name);
2300 VerifyDescriptor(descriptor);
2301 }
2302
2303 private:
2304 void VerifyDescriptor(const armnn::ResizeDescriptor& descriptor)
2305 {
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002306 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
2307 BOOST_CHECK(descriptor.m_TargetWidth == m_Descriptor.m_TargetWidth);
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002308 BOOST_CHECK(descriptor.m_TargetHeight == m_Descriptor.m_TargetHeight);
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002309 BOOST_CHECK(descriptor.m_Method == m_Descriptor.m_Method);
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002310 }
2311
2312 armnn::ResizeDescriptor m_Descriptor;
2313 };
2314
2315 const std::string layerName("resize");
2316 const armnn::TensorInfo inputInfo = armnn::TensorInfo({1, 3, 5, 5}, armnn::DataType::Float32);
2317 const armnn::TensorInfo outputInfo = armnn::TensorInfo({1, 3, 2, 4}, armnn::DataType::Float32);
2318
2319 armnn::ResizeDescriptor desc;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002320 desc.m_TargetWidth = 4;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002321 desc.m_TargetHeight = 2;
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01002322 desc.m_Method = armnn::ResizeMethod::NearestNeighbor;
FinnWilliamsArm6fb339a2019-06-28 15:07:10 +01002323
2324 armnn::INetworkPtr network = armnn::INetwork::Create();
2325 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2326 armnn::IConnectableLayer* const resizeLayer = network->AddResizeLayer(desc, layerName.c_str());
2327 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2328
2329 inputLayer->GetOutputSlot(0).Connect(resizeLayer->GetInputSlot(0));
2330 resizeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2331
2332 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2333 resizeLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2334
2335 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2336 BOOST_CHECK(deserializedNetwork);
2337
2338 ResizeLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2339 deserializedNetwork->Accept(verifier);
2340}
2341
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002342BOOST_AUTO_TEST_CASE(SerializeRsqrt)
2343{
2344 class RsqrtLayerVerifier : public LayerVerifierBase
2345 {
2346 public:
2347 RsqrtLayerVerifier(const std::string& layerName,
2348 const std::vector<armnn::TensorInfo>& inputInfos,
2349 const std::vector<armnn::TensorInfo>& outputInfos)
2350 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2351
2352 void VisitRsqrtLayer(const armnn::IConnectableLayer* layer, const char* name) override
2353 {
2354 VerifyNameAndConnections(layer, name);
2355 }
2356 };
2357
2358 const std::string layerName("rsqrt");
2359 const armnn::TensorInfo tensorInfo({ 3, 1, 2 }, armnn::DataType::Float32);
2360
2361 armnn::INetworkPtr network = armnn::INetwork::Create();
2362 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2363 armnn::IConnectableLayer* const rsqrtLayer = network->AddRsqrtLayer(layerName.c_str());
2364 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2365
2366 inputLayer->GetOutputSlot(0).Connect(rsqrtLayer->GetInputSlot(0));
2367 rsqrtLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2368
2369 inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2370 rsqrtLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
2371
2372 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2373 BOOST_CHECK(deserializedNetwork);
2374
2375 RsqrtLayerVerifier verifier(layerName, {tensorInfo}, {tensorInfo});
2376 deserializedNetwork->Accept(verifier);
2377}
2378
Aron Virginas-Tar2fda80b2019-09-18 13:36:52 +01002379BOOST_AUTO_TEST_CASE(SerializeSlice)
2380{
2381 class SliceLayerVerifier : public LayerVerifierBase
2382 {
2383 public:
2384 SliceLayerVerifier(const std::string& layerName,
2385 const std::vector<armnn::TensorInfo>& inputInfos,
2386 const std::vector<armnn::TensorInfo>& outputInfos,
2387 const armnn::SliceDescriptor& descriptor)
2388 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2389 , m_Descriptor(descriptor) {}
2390
2391 void VisitSliceLayer(const armnn::IConnectableLayer* layer,
2392 const armnn::SliceDescriptor& descriptor,
2393 const char* name) override
2394 {
2395 VerifyNameAndConnections(layer, name);
2396 VerifyDescriptor(descriptor);
2397 }
2398
2399 private:
2400 void VerifyDescriptor(const armnn::SliceDescriptor& descriptor)
2401 {
2402 BOOST_CHECK_EQUAL_COLLECTIONS(descriptor.m_Begin.begin(), descriptor.m_Begin.end(),
2403 m_Descriptor.m_Begin.begin(), m_Descriptor.m_Begin.end());
2404
2405 BOOST_CHECK_EQUAL_COLLECTIONS(descriptor.m_Size.begin(), descriptor.m_Size.end(),
2406 m_Descriptor.m_Size.begin(), m_Descriptor.m_Size.end());
2407 }
2408
2409 armnn::SliceDescriptor m_Descriptor;
2410 };
2411
2412 const std::string layerName{"slice"};
2413
2414 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2415 const armnn::TensorInfo outputInfo = armnn::TensorInfo({2, 2, 2, 1}, armnn::DataType::Float32);
2416
2417 armnn::SliceDescriptor descriptor({ 0, 0, 1, 0}, {2, 2, 2, 1});
2418
2419 armnn::INetworkPtr network = armnn::INetwork::Create();
2420
2421 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2422 armnn::IConnectableLayer* const sliceLayer = network->AddSliceLayer(descriptor, layerName.c_str());
2423 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2424
2425 inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
2426 sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2427
2428 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2429 sliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2430
2431 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2432 BOOST_CHECK(deserializedNetwork);
2433
2434 SliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor);
2435 deserializedNetwork->Accept(verifier);
2436}
2437
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002438BOOST_AUTO_TEST_CASE(SerializeSoftmax)
2439{
2440 class SoftmaxLayerVerifier : public LayerVerifierBase
2441 {
2442 public:
2443 SoftmaxLayerVerifier(const std::string& layerName,
2444 const std::vector<armnn::TensorInfo>& inputInfos,
2445 const std::vector<armnn::TensorInfo>& outputInfos,
2446 const armnn::SoftmaxDescriptor& descriptor)
2447 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2448 , m_Descriptor(descriptor) {}
2449
2450 void VisitSoftmaxLayer(const armnn::IConnectableLayer* layer,
2451 const armnn::SoftmaxDescriptor& descriptor,
2452 const char* name) override
2453 {
2454 VerifyNameAndConnections(layer, name);
2455 VerifyDescriptor(descriptor);
2456 }
2457
2458 private:
2459 void VerifyDescriptor(const armnn::SoftmaxDescriptor& descriptor)
2460 {
2461 BOOST_TEST(descriptor.m_Beta == m_Descriptor.m_Beta);
2462 }
2463
2464 armnn::SoftmaxDescriptor m_Descriptor;
2465 };
2466
2467 const std::string layerName("softmax");
2468 const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
2469
2470 armnn::SoftmaxDescriptor descriptor;
2471 descriptor.m_Beta = 1.0f;
2472
2473 armnn::INetworkPtr network = armnn::INetwork::Create();
2474 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2475 armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, layerName.c_str());
2476 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2477
2478 inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
2479 softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2480
2481 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2482 softmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
2483
2484 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2485 BOOST_CHECK(deserializedNetwork);
2486
2487 SoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
2488 deserializedNetwork->Accept(verifier);
2489}
2490
2491BOOST_AUTO_TEST_CASE(SerializeSpaceToBatchNd)
2492{
2493 class SpaceToBatchNdLayerVerifier : public LayerVerifierBase
2494 {
2495 public:
2496 SpaceToBatchNdLayerVerifier(const std::string& layerName,
2497 const std::vector<armnn::TensorInfo>& inputInfos,
2498 const std::vector<armnn::TensorInfo>& outputInfos,
2499 const armnn::SpaceToBatchNdDescriptor& descriptor)
2500 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2501 , m_Descriptor(descriptor) {}
2502
2503 void VisitSpaceToBatchNdLayer(const armnn::IConnectableLayer* layer,
2504 const armnn::SpaceToBatchNdDescriptor& descriptor,
2505 const char* name) override
2506 {
2507 VerifyNameAndConnections(layer, name);
2508 VerifyDescriptor(descriptor);
2509 }
2510
2511 private:
2512 void VerifyDescriptor(const armnn::SpaceToBatchNdDescriptor& descriptor)
2513 {
2514 BOOST_TEST(descriptor.m_PadList == m_Descriptor.m_PadList);
2515 BOOST_TEST(descriptor.m_BlockShape == m_Descriptor.m_BlockShape);
2516 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
2517 }
2518
2519 armnn::SpaceToBatchNdDescriptor m_Descriptor;
2520 };
2521
2522 const std::string layerName("spaceToBatchNd");
2523 const armnn::TensorInfo inputInfo({2, 1, 2, 4}, armnn::DataType::Float32);
2524 const armnn::TensorInfo outputInfo({8, 1, 1, 3}, armnn::DataType::Float32);
2525
2526 armnn::SpaceToBatchNdDescriptor desc;
2527 desc.m_DataLayout = armnn::DataLayout::NCHW;
2528 desc.m_BlockShape = {2, 2};
2529 desc.m_PadList = {{0, 0}, {2, 0}};
2530
2531 armnn::INetworkPtr network = armnn::INetwork::Create();
2532 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2533 armnn::IConnectableLayer* const spaceToBatchNdLayer = network->AddSpaceToBatchNdLayer(desc, layerName.c_str());
2534 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2535
2536 inputLayer->GetOutputSlot(0).Connect(spaceToBatchNdLayer->GetInputSlot(0));
2537 spaceToBatchNdLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2538
2539 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2540 spaceToBatchNdLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2541
2542 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2543 BOOST_CHECK(deserializedNetwork);
2544
2545 SpaceToBatchNdLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2546 deserializedNetwork->Accept(verifier);
2547}
2548
Aron Virginas-Taraa067142019-06-11 16:01:44 +01002549BOOST_AUTO_TEST_CASE(SerializeSpaceToDepth)
2550{
2551 class SpaceToDepthLayerVerifier : public LayerVerifierBase
2552 {
2553 public:
2554 SpaceToDepthLayerVerifier(const std::string& layerName,
2555 const std::vector<armnn::TensorInfo>& inputInfos,
2556 const std::vector<armnn::TensorInfo>& outputInfos,
2557 const armnn::SpaceToDepthDescriptor& descriptor)
2558 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2559 , m_Descriptor(descriptor) {}
2560
2561 void VisitSpaceToDepthLayer(const armnn::IConnectableLayer* layer,
2562 const armnn::SpaceToDepthDescriptor& descriptor,
2563 const char* name) override
2564 {
2565 VerifyNameAndConnections(layer, name);
2566 VerifyDescriptor(descriptor);
2567 }
2568
2569 private:
2570 void VerifyDescriptor(const armnn::SpaceToDepthDescriptor& descriptor)
2571 {
2572 BOOST_TEST(descriptor.m_BlockSize == m_Descriptor.m_BlockSize);
2573 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
2574 }
2575
2576 armnn::SpaceToDepthDescriptor m_Descriptor;
2577 };
2578
2579 const std::string layerName("spaceToDepth");
2580
2581 const armnn::TensorInfo inputInfo ({ 1, 16, 8, 3 }, armnn::DataType::Float32);
2582 const armnn::TensorInfo outputInfo({ 1, 8, 4, 12 }, armnn::DataType::Float32);
2583
2584 armnn::SpaceToDepthDescriptor desc;
2585 desc.m_BlockSize = 2;
2586 desc.m_DataLayout = armnn::DataLayout::NHWC;
2587
2588 armnn::INetworkPtr network = armnn::INetwork::Create();
2589 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2590 armnn::IConnectableLayer* const spaceToDepthLayer = network->AddSpaceToDepthLayer(desc, layerName.c_str());
2591 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2592
2593 inputLayer->GetOutputSlot(0).Connect(spaceToDepthLayer->GetInputSlot(0));
2594 spaceToDepthLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2595
2596 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2597 spaceToDepthLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2598
2599 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2600 BOOST_CHECK(deserializedNetwork);
2601
2602 SpaceToDepthLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2603 deserializedNetwork->Accept(verifier);
2604}
2605
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002606BOOST_AUTO_TEST_CASE(SerializeSplitter)
2607{
2608 class SplitterLayerVerifier : public LayerVerifierBase
2609 {
2610 public:
2611 SplitterLayerVerifier(const std::string& layerName,
2612 const std::vector<armnn::TensorInfo>& inputInfos,
2613 const std::vector<armnn::TensorInfo>& outputInfos,
2614 const armnn::ViewsDescriptor& descriptor)
2615 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2616 , m_Descriptor(descriptor) {}
2617
2618 void VisitSplitterLayer(const armnn::IConnectableLayer* layer,
2619 const armnn::ViewsDescriptor& descriptor,
2620 const char* name) override
2621 {
2622 VerifyNameAndConnections(layer, name);
2623 VerifyDescriptor(descriptor);
2624 }
2625
2626 private:
2627 void VerifyDescriptor(const armnn::ViewsDescriptor& descriptor)
2628 {
2629 BOOST_TEST(descriptor.GetNumViews() == m_Descriptor.GetNumViews());
2630 BOOST_TEST(descriptor.GetNumDimensions() == m_Descriptor.GetNumDimensions());
2631
2632 for (uint32_t i = 0; i < descriptor.GetNumViews(); i++)
2633 {
2634 for (uint32_t j = 0; j < descriptor.GetNumDimensions(); j++)
2635 {
2636 BOOST_TEST(descriptor.GetViewOrigin(i)[j] == m_Descriptor.GetViewOrigin(i)[j]);
2637 BOOST_TEST(descriptor.GetViewSizes(i)[j] == m_Descriptor.GetViewSizes(i)[j]);
2638 }
2639 }
2640 }
2641
2642 armnn::ViewsDescriptor m_Descriptor;
2643 };
2644
2645 const unsigned int numViews = 3;
2646 const unsigned int numDimensions = 4;
2647 const unsigned int inputShape[] = {1, 18, 4, 4};
2648 const unsigned int outputShape[] = {1, 6, 4, 4};
2649
2650 // This is modelled on how the caffe parser sets up a splitter layer to partition an input along dimension one.
2651 unsigned int splitterDimSizes[4] = {static_cast<unsigned int>(inputShape[0]),
2652 static_cast<unsigned int>(inputShape[1]),
2653 static_cast<unsigned int>(inputShape[2]),
2654 static_cast<unsigned int>(inputShape[3])};
2655 splitterDimSizes[1] /= numViews;
2656 armnn::ViewsDescriptor desc(numViews, numDimensions);
2657
2658 for (unsigned int g = 0; g < numViews; ++g)
2659 {
2660 desc.SetViewOriginCoord(g, 1, splitterDimSizes[1] * g);
2661
2662 for (unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
2663 {
2664 desc.SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
2665 }
2666 }
2667
2668 const std::string layerName("splitter");
2669 const armnn::TensorInfo inputInfo(numDimensions, inputShape, armnn::DataType::Float32);
2670 const armnn::TensorInfo outputInfo(numDimensions, outputShape, armnn::DataType::Float32);
2671
2672 armnn::INetworkPtr network = armnn::INetwork::Create();
2673 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2674 armnn::IConnectableLayer* const splitterLayer = network->AddSplitterLayer(desc, layerName.c_str());
2675 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
2676 armnn::IConnectableLayer* const outputLayer1 = network->AddOutputLayer(1);
2677 armnn::IConnectableLayer* const outputLayer2 = network->AddOutputLayer(2);
2678
2679 inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
2680 splitterLayer->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
2681 splitterLayer->GetOutputSlot(1).Connect(outputLayer1->GetInputSlot(0));
2682 splitterLayer->GetOutputSlot(2).Connect(outputLayer2->GetInputSlot(0));
2683
2684 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2685 splitterLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2686 splitterLayer->GetOutputSlot(1).SetTensorInfo(outputInfo);
2687 splitterLayer->GetOutputSlot(2).SetTensorInfo(outputInfo);
2688
2689 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2690 BOOST_CHECK(deserializedNetwork);
2691
2692 SplitterLayerVerifier verifier(layerName, {inputInfo}, {outputInfo, outputInfo, outputInfo}, desc);
2693 deserializedNetwork->Accept(verifier);
2694}
2695
Matthew Jacksonb5433ee2019-07-11 15:54:20 +01002696BOOST_AUTO_TEST_CASE(SerializeStack)
2697{
2698 class StackLayerVerifier : public LayerVerifierBase
2699 {
2700 public:
2701 StackLayerVerifier(const std::string& layerName,
2702 const std::vector<armnn::TensorInfo>& inputInfos,
2703 const std::vector<armnn::TensorInfo>& outputInfos,
2704 const armnn::StackDescriptor& descriptor)
2705 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2706 , m_Descriptor(descriptor) {}
2707
2708 void VisitStackLayer(const armnn::IConnectableLayer* layer,
2709 const armnn::StackDescriptor& descriptor,
2710 const char* name) override
2711 {
2712 VerifyNameAndConnections(layer, name);
2713 VerifyDescriptor(descriptor);
2714 }
2715
2716 private:
2717 void VerifyDescriptor(const armnn::StackDescriptor& descriptor)
2718 {
2719 BOOST_TEST(descriptor.m_Axis == m_Descriptor.m_Axis);
2720 BOOST_TEST(descriptor.m_InputShape == m_Descriptor.m_InputShape);
2721 BOOST_TEST(descriptor.m_NumInputs == m_Descriptor.m_NumInputs);
2722 }
2723
2724 armnn::StackDescriptor m_Descriptor;
2725 };
2726
2727 const std::string layerName("stack");
2728
2729 armnn::TensorInfo inputTensorInfo ({4, 3, 5}, armnn::DataType::Float32);
2730 armnn::TensorInfo outputTensorInfo({4, 3, 2, 5}, armnn::DataType::Float32);
2731
2732 armnn::StackDescriptor descriptor(2, 2, {4, 3, 5});
2733
2734 armnn::INetworkPtr network = armnn::INetwork::Create();
2735 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(0);
2736 armnn::IConnectableLayer* const inputLayer2 = network->AddInputLayer(1);
2737 armnn::IConnectableLayer* const stackLayer = network->AddStackLayer(descriptor, layerName.c_str());
2738 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2739
2740 inputLayer1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
2741 inputLayer2->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
2742 stackLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2743
2744 inputLayer1->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2745 inputLayer2->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
2746 stackLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
2747
2748 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2749 BOOST_CHECK(deserializedNetwork);
2750
2751 StackLayerVerifier verifier(layerName, {inputTensorInfo, inputTensorInfo}, {outputTensorInfo}, descriptor);
2752 deserializedNetwork->Accept(verifier);
2753}
2754
Nattapat Chaimanowong03acd682019-03-20 11:19:52 +00002755BOOST_AUTO_TEST_CASE(SerializeStridedSlice)
2756{
2757 class StridedSliceLayerVerifier : public LayerVerifierBase
2758 {
2759 public:
2760 StridedSliceLayerVerifier(const std::string& layerName,
2761 const std::vector<armnn::TensorInfo>& inputInfos,
2762 const std::vector<armnn::TensorInfo>& outputInfos,
2763 const armnn::StridedSliceDescriptor& descriptor)
2764 : LayerVerifierBase(layerName, inputInfos, outputInfos)
2765 , m_Descriptor(descriptor) {}
2766
2767 void VisitStridedSliceLayer(const armnn::IConnectableLayer* layer,
2768 const armnn::StridedSliceDescriptor& descriptor,
2769 const char* name) override
2770 {
2771 VerifyNameAndConnections(layer, name);
2772 VerifyDescriptor(descriptor);
2773 }
2774
2775 private:
2776 void VerifyDescriptor(const armnn::StridedSliceDescriptor& descriptor)
2777 {
2778 BOOST_TEST(descriptor.m_Begin == m_Descriptor.m_Begin);
2779 BOOST_TEST(descriptor.m_End == m_Descriptor.m_End);
2780 BOOST_TEST(descriptor.m_Stride == m_Descriptor.m_Stride);
2781 BOOST_TEST(descriptor.m_BeginMask == m_Descriptor.m_BeginMask);
2782 BOOST_TEST(descriptor.m_EndMask == m_Descriptor.m_EndMask);
2783 BOOST_TEST(descriptor.m_ShrinkAxisMask == m_Descriptor.m_ShrinkAxisMask);
2784 BOOST_TEST(descriptor.m_EllipsisMask == m_Descriptor.m_EllipsisMask);
2785 BOOST_TEST(descriptor.m_NewAxisMask == m_Descriptor.m_NewAxisMask);
2786 BOOST_TEST(GetDataLayoutName(descriptor.m_DataLayout) == GetDataLayoutName(m_Descriptor.m_DataLayout));
2787 }
2788 armnn::StridedSliceDescriptor m_Descriptor;
2789 };
2790
2791 const std::string layerName("stridedSlice");
2792 const armnn::TensorInfo inputInfo = armnn::TensorInfo({3, 2, 3, 1}, armnn::DataType::Float32);
2793 const armnn::TensorInfo outputInfo = armnn::TensorInfo({3, 1}, armnn::DataType::Float32);
2794
2795 armnn::StridedSliceDescriptor desc({0, 0, 1, 0}, {1, 1, 1, 1}, {1, 1, 1, 1});
2796 desc.m_EndMask = (1 << 4) - 1;
2797 desc.m_ShrinkAxisMask = (1 << 1) | (1 << 2);
2798 desc.m_DataLayout = armnn::DataLayout::NCHW;
2799
2800 armnn::INetworkPtr network = armnn::INetwork::Create();
2801 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2802 armnn::IConnectableLayer* const stridedSliceLayer = network->AddStridedSliceLayer(desc, layerName.c_str());
2803 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2804
2805 inputLayer->GetOutputSlot(0).Connect(stridedSliceLayer->GetInputSlot(0));
2806 stridedSliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2807
2808 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
2809 stridedSliceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
2810
2811 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2812 BOOST_CHECK(deserializedNetwork);
2813
2814 StridedSliceLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, desc);
2815 deserializedNetwork->Accept(verifier);
2816}
2817
2818BOOST_AUTO_TEST_CASE(SerializeSubtraction)
2819{
2820 class SubtractionLayerVerifier : public LayerVerifierBase
2821 {
2822 public:
2823 SubtractionLayerVerifier(const std::string& layerName,
2824 const std::vector<armnn::TensorInfo>& inputInfos,
2825 const std::vector<armnn::TensorInfo>& outputInfos)
2826 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2827
2828 void VisitSubtractionLayer(const armnn::IConnectableLayer* layer, const char* name) override
2829 {
2830 VerifyNameAndConnections(layer, name);
2831 }
2832 };
2833
2834 const std::string layerName("subtraction");
2835 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2836
2837 armnn::INetworkPtr network = armnn::INetwork::Create();
2838 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
2839 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
2840 armnn::IConnectableLayer* const subtractionLayer = network->AddSubtractionLayer(layerName.c_str());
2841 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2842
2843 inputLayer0->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(0));
2844 inputLayer1->GetOutputSlot(0).Connect(subtractionLayer->GetInputSlot(1));
2845 subtractionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2846
2847 inputLayer0->GetOutputSlot(0).SetTensorInfo(info);
2848 inputLayer1->GetOutputSlot(0).SetTensorInfo(info);
2849 subtractionLayer->GetOutputSlot(0).SetTensorInfo(info);
2850
2851 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2852 BOOST_CHECK(deserializedNetwork);
2853
2854 SubtractionLayerVerifier verifier(layerName, {info, info}, {info});
2855 deserializedNetwork->Accept(verifier);
Nattapat Chaimanowong3e14a9d2019-03-18 12:37:06 +00002856}
2857
Sadik Armaganeff363d2019-04-05 15:25:46 +01002858BOOST_AUTO_TEST_CASE(SerializeSwitch)
2859{
2860 class SwitchLayerVerifier : public LayerVerifierBase
2861 {
2862 public:
2863 SwitchLayerVerifier(const std::string& layerName,
2864 const std::vector<armnn::TensorInfo>& inputInfos,
2865 const std::vector<armnn::TensorInfo>& outputInfos)
2866 : LayerVerifierBase(layerName, inputInfos, outputInfos) {}
2867
2868 void VisitSwitchLayer(const armnn::IConnectableLayer* layer, const char* name) override
2869 {
2870 VerifyNameAndConnections(layer, name);
2871 }
2872
2873 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
2874 const armnn::ConstTensor& input,
2875 const char *name) override {}
2876 };
2877
2878 const std::string layerName("switch");
2879 const armnn::TensorInfo info({ 1, 4 }, armnn::DataType::Float32);
2880
2881 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
2882 armnn::ConstTensor constTensor(info, constantData);
2883
2884 armnn::INetworkPtr network = armnn::INetwork::Create();
2885 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2886 armnn::IConnectableLayer* const constantLayer = network->AddConstantLayer(constTensor, "constant");
2887 armnn::IConnectableLayer* const switchLayer = network->AddSwitchLayer(layerName.c_str());
2888 armnn::IConnectableLayer* const trueOutputLayer = network->AddOutputLayer(0);
2889 armnn::IConnectableLayer* const falseOutputLayer = network->AddOutputLayer(1);
2890
2891 inputLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(0));
2892 constantLayer->GetOutputSlot(0).Connect(switchLayer->GetInputSlot(1));
2893 switchLayer->GetOutputSlot(0).Connect(trueOutputLayer->GetInputSlot(0));
2894 switchLayer->GetOutputSlot(1).Connect(falseOutputLayer->GetInputSlot(0));
2895
2896 inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2897 constantLayer->GetOutputSlot(0).SetTensorInfo(info);
2898 switchLayer->GetOutputSlot(0).SetTensorInfo(info);
2899 switchLayer->GetOutputSlot(1).SetTensorInfo(info);
2900
2901 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
2902 BOOST_CHECK(deserializedNetwork);
2903
2904 SwitchLayerVerifier verifier(layerName, {info, info}, {info, info});
2905 deserializedNetwork->Accept(verifier);
2906}
2907
Aron Virginas-Tarcb549302019-06-21 13:53:38 +01002908BOOST_AUTO_TEST_CASE(SerializeTransposeConvolution2d)
2909{
2910 class TransposeConvolution2dLayerVerifier : public LayerVerifierBase
2911 {
2912 public:
2913 TransposeConvolution2dLayerVerifier(const std::string& layerName,
2914 const std::vector<armnn::TensorInfo>& inputInfos,
2915 const std::vector<armnn::TensorInfo>& outputInfos,
2916 const armnn::TransposeConvolution2dDescriptor& descriptor,
2917 const armnn::ConstTensor& weights,
2918 const armnn::Optional<armnn::ConstTensor>& biases) :
2919 LayerVerifierBase(layerName, inputInfos, outputInfos),
2920 m_Descriptor(descriptor),
2921 m_Weights(weights),
2922 m_Biases(biases)
2923 {}
2924
2925 void VisitTransposeConvolution2dLayer(const armnn::IConnectableLayer* layer,
2926 const armnn::TransposeConvolution2dDescriptor& descriptor,
2927 const armnn::ConstTensor& weights,
2928 const armnn::Optional<armnn::ConstTensor>& biases,
2929 const char* name) override
2930 {
2931 VerifyNameAndConnections(layer, name);
2932 VerifyDescriptor(descriptor);
2933
2934 // check weights
2935 CompareConstTensor(weights, m_Weights);
2936
2937 // check biases
2938 BOOST_CHECK(biases.has_value() == descriptor.m_BiasEnabled);
2939 BOOST_CHECK(m_Biases.has_value() == m_Descriptor.m_BiasEnabled);
2940
2941 BOOST_CHECK(biases.has_value() == m_Biases.has_value());
2942
2943 if (biases.has_value() && m_Biases.has_value())
2944 {
2945 CompareConstTensor(biases.value(), m_Biases.value());
2946 }
2947 }
2948
2949 private:
2950 void VerifyDescriptor(const armnn::TransposeConvolution2dDescriptor& descriptor)
2951 {
2952 BOOST_CHECK(descriptor.m_PadLeft == m_Descriptor.m_PadLeft);
2953 BOOST_CHECK(descriptor.m_PadRight == m_Descriptor.m_PadRight);
2954 BOOST_CHECK(descriptor.m_PadTop == m_Descriptor.m_PadTop);
2955 BOOST_CHECK(descriptor.m_PadBottom == m_Descriptor.m_PadBottom);
2956 BOOST_CHECK(descriptor.m_StrideX == m_Descriptor.m_StrideX);
2957 BOOST_CHECK(descriptor.m_StrideY == m_Descriptor.m_StrideY);
2958 BOOST_CHECK(descriptor.m_BiasEnabled == m_Descriptor.m_BiasEnabled);
2959 BOOST_CHECK(descriptor.m_DataLayout == m_Descriptor.m_DataLayout);
2960 }
2961
2962 armnn::TransposeConvolution2dDescriptor m_Descriptor;
2963 armnn::ConstTensor m_Weights;
2964 armnn::Optional<armnn::ConstTensor> m_Biases;
2965 };
2966
2967 const std::string layerName("transposeConvolution2d");
2968 const armnn::TensorInfo inputInfo ({ 1, 7, 7, 1 }, armnn::DataType::Float32);
2969 const armnn::TensorInfo outputInfo({ 1, 9, 9, 1 }, armnn::DataType::Float32);
2970
2971 const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
2972 const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
2973
2974 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
2975 armnn::ConstTensor weights(weightsInfo, weightsData);
2976
2977 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
2978 armnn::ConstTensor biases(biasesInfo, biasesData);
2979
2980 armnn::TransposeConvolution2dDescriptor descriptor;
2981 descriptor.m_PadLeft = 1;
2982 descriptor.m_PadRight = 1;
2983 descriptor.m_PadTop = 1;
2984 descriptor.m_PadBottom = 1;
2985 descriptor.m_StrideX = 1;
2986 descriptor.m_StrideY = 1;
2987 descriptor.m_BiasEnabled = true;
2988 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
2989
2990 armnn::INetworkPtr network = armnn::INetwork::Create();
2991 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
2992 armnn::IConnectableLayer* const convLayer =
2993 network->AddTransposeConvolution2dLayer(descriptor,
2994 weights,
2995 armnn::Optional<armnn::ConstTensor>(biases),
2996 layerName.c_str());
2997 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
2998
2999 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
3000 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
3001
3002 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
3003 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
3004
3005 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3006 BOOST_CHECK(deserializedNetwork);
3007
3008 TransposeConvolution2dLayerVerifier verifier(layerName, {inputInfo}, {outputInfo}, descriptor, weights, biases);
3009 deserializedNetwork->Accept(verifier);
3010}
3011
Sadik Armagandb059fd2019-03-20 12:28:32 +00003012BOOST_AUTO_TEST_CASE(SerializeDeserializeNonLinearNetwork)
3013{
3014 class ConstantLayerVerifier : public LayerVerifierBase
3015 {
3016 public:
3017 ConstantLayerVerifier(const std::string& layerName,
3018 const std::vector<armnn::TensorInfo>& inputInfos,
3019 const std::vector<armnn::TensorInfo>& outputInfos,
3020 const armnn::ConstTensor& layerInput)
3021 : LayerVerifierBase(layerName, inputInfos, outputInfos)
3022 , m_LayerInput(layerInput) {}
3023
3024 void VisitConstantLayer(const armnn::IConnectableLayer* layer,
3025 const armnn::ConstTensor& input,
3026 const char* name) override
3027 {
3028 VerifyNameAndConnections(layer, name);
3029
3030 CompareConstTensor(input, m_LayerInput);
3031 }
3032
3033 void VisitAdditionLayer(const armnn::IConnectableLayer* layer, const char* name = nullptr) override {}
3034
3035 private:
3036 armnn::ConstTensor m_LayerInput;
3037 };
3038
3039 const std::string layerName("constant");
3040 const armnn::TensorInfo info({ 2, 3 }, armnn::DataType::Float32);
3041
3042 std::vector<float> constantData = GenerateRandomData<float>(info.GetNumElements());
3043 armnn::ConstTensor constTensor(info, constantData);
3044
3045 armnn::INetworkPtr network(armnn::INetwork::Create());
3046 armnn::IConnectableLayer* input = network->AddInputLayer(0);
3047 armnn::IConnectableLayer* add = network->AddAdditionLayer();
3048 armnn::IConnectableLayer* constant = network->AddConstantLayer(constTensor, layerName.c_str());
3049 armnn::IConnectableLayer* output = network->AddOutputLayer(0);
3050
3051 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
3052 constant->GetOutputSlot(0).Connect(add->GetInputSlot(1));
3053 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
3054
3055 input->GetOutputSlot(0).SetTensorInfo(info);
3056 constant->GetOutputSlot(0).SetTensorInfo(info);
3057 add->GetOutputSlot(0).SetTensorInfo(info);
3058
3059 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3060 BOOST_CHECK(deserializedNetwork);
3061
3062 ConstantLayerVerifier verifier(layerName, {}, {info}, constTensor);
3063 deserializedNetwork->Accept(verifier);
3064}
3065
Jim Flynn11af3752019-03-19 17:22:29 +00003066class VerifyLstmLayer : public LayerVerifierBase
3067{
3068public:
3069 VerifyLstmLayer(const std::string& layerName,
3070 const std::vector<armnn::TensorInfo>& inputInfos,
3071 const std::vector<armnn::TensorInfo>& outputInfos,
3072 const armnn::LstmDescriptor& descriptor,
3073 const armnn::LstmInputParams& inputParams) :
3074 LayerVerifierBase(layerName, inputInfos, outputInfos), m_Descriptor(descriptor), m_InputParams(inputParams)
3075 {
3076 }
3077 void VisitLstmLayer(const armnn::IConnectableLayer* layer,
3078 const armnn::LstmDescriptor& descriptor,
3079 const armnn::LstmInputParams& params,
3080 const char* name)
3081 {
3082 VerifyNameAndConnections(layer, name);
3083 VerifyDescriptor(descriptor);
3084 VerifyInputParameters(params);
3085 }
3086protected:
3087 void VerifyDescriptor(const armnn::LstmDescriptor& descriptor)
3088 {
3089 BOOST_TEST(m_Descriptor.m_ActivationFunc == descriptor.m_ActivationFunc);
3090 BOOST_TEST(m_Descriptor.m_ClippingThresCell == descriptor.m_ClippingThresCell);
3091 BOOST_TEST(m_Descriptor.m_ClippingThresProj == descriptor.m_ClippingThresProj);
3092 BOOST_TEST(m_Descriptor.m_CifgEnabled == descriptor.m_CifgEnabled);
3093 BOOST_TEST(m_Descriptor.m_PeepholeEnabled = descriptor.m_PeepholeEnabled);
3094 BOOST_TEST(m_Descriptor.m_ProjectionEnabled == descriptor.m_ProjectionEnabled);
Jan Eilersf8c62972019-07-17 11:07:49 +01003095 BOOST_TEST(m_Descriptor.m_LayerNormEnabled == descriptor.m_LayerNormEnabled);
Jim Flynn11af3752019-03-19 17:22:29 +00003096 }
3097 void VerifyInputParameters(const armnn::LstmInputParams& params)
3098 {
3099 VerifyConstTensors(
3100 "m_InputToInputWeights", m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
3101 VerifyConstTensors(
3102 "m_InputToForgetWeights", m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
3103 VerifyConstTensors(
3104 "m_InputToCellWeights", m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
3105 VerifyConstTensors(
3106 "m_InputToOutputWeights", m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
3107 VerifyConstTensors(
3108 "m_RecurrentToInputWeights", m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
3109 VerifyConstTensors(
3110 "m_RecurrentToForgetWeights", m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
3111 VerifyConstTensors(
3112 "m_RecurrentToCellWeights", m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
3113 VerifyConstTensors(
3114 "m_RecurrentToOutputWeights", m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
3115 VerifyConstTensors(
3116 "m_CellToInputWeights", m_InputParams.m_CellToInputWeights, params.m_CellToInputWeights);
3117 VerifyConstTensors(
3118 "m_CellToForgetWeights", m_InputParams.m_CellToForgetWeights, params.m_CellToForgetWeights);
3119 VerifyConstTensors(
3120 "m_CellToOutputWeights", m_InputParams.m_CellToOutputWeights, params.m_CellToOutputWeights);
3121 VerifyConstTensors(
3122 "m_InputGateBias", m_InputParams.m_InputGateBias, params.m_InputGateBias);
3123 VerifyConstTensors(
3124 "m_ForgetGateBias", m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
3125 VerifyConstTensors(
3126 "m_CellBias", m_InputParams.m_CellBias, params.m_CellBias);
3127 VerifyConstTensors(
3128 "m_OutputGateBias", m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
3129 VerifyConstTensors(
3130 "m_ProjectionWeights", m_InputParams.m_ProjectionWeights, params.m_ProjectionWeights);
3131 VerifyConstTensors(
3132 "m_ProjectionBias", m_InputParams.m_ProjectionBias, params.m_ProjectionBias);
Jan Eilersf8c62972019-07-17 11:07:49 +01003133 VerifyConstTensors(
3134 "m_InputLayerNormWeights", m_InputParams.m_InputLayerNormWeights, params.m_InputLayerNormWeights);
3135 VerifyConstTensors(
3136 "m_ForgetLayerNormWeights", m_InputParams.m_ForgetLayerNormWeights, params.m_ForgetLayerNormWeights);
3137 VerifyConstTensors(
3138 "m_CellLayerNormWeights", m_InputParams.m_CellLayerNormWeights, params.m_CellLayerNormWeights);
3139 VerifyConstTensors(
3140 "m_OutputLayerNormWeights", m_InputParams.m_OutputLayerNormWeights, params.m_OutputLayerNormWeights);
Jim Flynn11af3752019-03-19 17:22:29 +00003141 }
Jim Flynn11af3752019-03-19 17:22:29 +00003142private:
3143 armnn::LstmDescriptor m_Descriptor;
3144 armnn::LstmInputParams m_InputParams;
3145};
3146
3147BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmCifgPeepholeNoProjection)
3148{
3149 armnn::LstmDescriptor descriptor;
3150 descriptor.m_ActivationFunc = 4;
3151 descriptor.m_ClippingThresProj = 0.0f;
3152 descriptor.m_ClippingThresCell = 0.0f;
3153 descriptor.m_CifgEnabled = true; // if this is true then we DON'T need to set the OptCifgParams
3154 descriptor.m_ProjectionEnabled = false;
3155 descriptor.m_PeepholeEnabled = true;
3156
3157 const uint32_t batchSize = 1;
3158 const uint32_t inputSize = 2;
3159 const uint32_t numUnits = 4;
3160 const uint32_t outputSize = numUnits;
3161
3162 armnn::TensorInfo inputWeightsInfo1({numUnits, inputSize}, armnn::DataType::Float32);
3163 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3164 armnn::ConstTensor inputToForgetWeights(inputWeightsInfo1, inputToForgetWeightsData);
3165
3166 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3167 armnn::ConstTensor inputToCellWeights(inputWeightsInfo1, inputToCellWeightsData);
3168
3169 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo1.GetNumElements());
3170 armnn::ConstTensor inputToOutputWeights(inputWeightsInfo1, inputToOutputWeightsData);
3171
3172 armnn::TensorInfo inputWeightsInfo2({numUnits, outputSize}, armnn::DataType::Float32);
3173 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3174 armnn::ConstTensor recurrentToForgetWeights(inputWeightsInfo2, recurrentToForgetWeightsData);
3175
3176 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3177 armnn::ConstTensor recurrentToCellWeights(inputWeightsInfo2, recurrentToCellWeightsData);
3178
3179 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo2.GetNumElements());
3180 armnn::ConstTensor recurrentToOutputWeights(inputWeightsInfo2, recurrentToOutputWeightsData);
3181
3182 armnn::TensorInfo inputWeightsInfo3({numUnits}, armnn::DataType::Float32);
3183 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3184 armnn::ConstTensor cellToForgetWeights(inputWeightsInfo3, cellToForgetWeightsData);
3185
3186 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(inputWeightsInfo3.GetNumElements());
3187 armnn::ConstTensor cellToOutputWeights(inputWeightsInfo3, cellToOutputWeightsData);
3188
3189 std::vector<float> forgetGateBiasData(numUnits, 1.0f);
3190 armnn::ConstTensor forgetGateBias(inputWeightsInfo3, forgetGateBiasData);
3191
3192 std::vector<float> cellBiasData(numUnits, 0.0f);
3193 armnn::ConstTensor cellBias(inputWeightsInfo3, cellBiasData);
3194
3195 std::vector<float> outputGateBiasData(numUnits, 0.0f);
3196 armnn::ConstTensor outputGateBias(inputWeightsInfo3, outputGateBiasData);
3197
3198 armnn::LstmInputParams params;
3199 params.m_InputToForgetWeights = &inputToForgetWeights;
3200 params.m_InputToCellWeights = &inputToCellWeights;
3201 params.m_InputToOutputWeights = &inputToOutputWeights;
3202 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3203 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3204 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3205 params.m_ForgetGateBias = &forgetGateBias;
3206 params.m_CellBias = &cellBias;
3207 params.m_OutputGateBias = &outputGateBias;
3208 params.m_CellToForgetWeights = &cellToForgetWeights;
3209 params.m_CellToOutputWeights = &cellToOutputWeights;
3210
3211 armnn::INetworkPtr network = armnn::INetwork::Create();
3212 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3213 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3214 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3215 const std::string layerName("lstm");
3216 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3217 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3218 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3219 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3220 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3221
3222 // connect up
3223 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3224 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3225 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3226 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 3 }, armnn::DataType::Float32);
3227
3228 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3229 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3230
3231 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3232 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3233
3234 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3235 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3236
3237 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3238 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3239
3240 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3241 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3242
3243 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3244 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3245
3246 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3247 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3248
3249 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3250 BOOST_CHECK(deserializedNetwork);
3251
3252 VerifyLstmLayer checker(
3253 layerName,
3254 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3255 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3256 descriptor,
3257 params);
3258 deserializedNetwork->Accept(checker);
3259}
3260
3261BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeAndProjection)
3262{
3263 armnn::LstmDescriptor descriptor;
3264 descriptor.m_ActivationFunc = 4;
3265 descriptor.m_ClippingThresProj = 0.0f;
3266 descriptor.m_ClippingThresCell = 0.0f;
3267 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3268 descriptor.m_ProjectionEnabled = true;
3269 descriptor.m_PeepholeEnabled = true;
3270
3271 const uint32_t batchSize = 2;
3272 const uint32_t inputSize = 5;
3273 const uint32_t numUnits = 20;
3274 const uint32_t outputSize = 16;
3275
3276 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3277 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3278 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3279
3280 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3281 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3282
3283 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3284 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3285
3286 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3287 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3288
3289 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3290 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3291 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3292
3293 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3294 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3295
3296 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3297 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3298
3299 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3300 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3301
3302 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3303 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3304 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3305
3306 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3307 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3308
3309 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3310 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3311
3312 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3313 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3314
3315 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3316 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3317
3318 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3319 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3320
3321 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3322 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3323
3324 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3325 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3326 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3327
3328 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3329 std::vector<float> projectionBiasData(outputSize, 0.f);
3330 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3331
3332 armnn::LstmInputParams params;
3333 params.m_InputToForgetWeights = &inputToForgetWeights;
3334 params.m_InputToCellWeights = &inputToCellWeights;
3335 params.m_InputToOutputWeights = &inputToOutputWeights;
3336 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3337 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3338 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3339 params.m_ForgetGateBias = &forgetGateBias;
3340 params.m_CellBias = &cellBias;
3341 params.m_OutputGateBias = &outputGateBias;
3342
3343 // additional params because: descriptor.m_CifgEnabled = false
3344 params.m_InputToInputWeights = &inputToInputWeights;
3345 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3346 params.m_CellToInputWeights = &cellToInputWeights;
3347 params.m_InputGateBias = &inputGateBias;
3348
3349 // additional params because: descriptor.m_ProjectionEnabled = true
3350 params.m_ProjectionWeights = &projectionWeights;
3351 params.m_ProjectionBias = &projectionBias;
3352
3353 // additional params because: descriptor.m_PeepholeEnabled = true
3354 params.m_CellToForgetWeights = &cellToForgetWeights;
3355 params.m_CellToOutputWeights = &cellToOutputWeights;
3356
3357 armnn::INetworkPtr network = armnn::INetwork::Create();
3358 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3359 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3360 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3361 const std::string layerName("lstm");
3362 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3363 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3364 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3365 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3366 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3367
3368 // connect up
3369 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3370 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3371 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3372 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3373
3374 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3375 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3376
3377 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3378 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3379
3380 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3381 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3382
3383 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3384 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3385
3386 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3387 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3388
3389 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3390 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3391
3392 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3393 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3394
3395 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3396 BOOST_CHECK(deserializedNetwork);
3397
3398 VerifyLstmLayer checker(
3399 layerName,
3400 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3401 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3402 descriptor,
3403 params);
3404 deserializedNetwork->Accept(checker);
3405}
3406
Jan Eilersf8c62972019-07-17 11:07:49 +01003407BOOST_AUTO_TEST_CASE(SerializeDeserializeLstmNoCifgWithPeepholeWithProjectionWithLayerNorm)
3408{
3409 armnn::LstmDescriptor descriptor;
3410 descriptor.m_ActivationFunc = 4;
3411 descriptor.m_ClippingThresProj = 0.0f;
3412 descriptor.m_ClippingThresCell = 0.0f;
3413 descriptor.m_CifgEnabled = false; // if this is true then we DON'T need to set the OptCifgParams
3414 descriptor.m_ProjectionEnabled = true;
3415 descriptor.m_PeepholeEnabled = true;
3416 descriptor.m_LayerNormEnabled = true;
3417
3418 const uint32_t batchSize = 2;
3419 const uint32_t inputSize = 5;
3420 const uint32_t numUnits = 20;
3421 const uint32_t outputSize = 16;
3422
3423 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
3424 std::vector<float> inputToInputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3425 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
3426
3427 std::vector<float> inputToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3428 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
3429
3430 std::vector<float> inputToCellWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3431 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
3432
3433 std::vector<float> inputToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x5.GetNumElements());
3434 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
3435
3436 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
3437 std::vector<float> inputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3438 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
3439
3440 std::vector<float> forgetGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3441 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
3442
3443 std::vector<float> cellBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3444 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
3445
3446 std::vector<float> outputGateBiasData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3447 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
3448
3449 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
3450 std::vector<float> recurrentToInputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3451 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
3452
3453 std::vector<float> recurrentToForgetWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3454 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
3455
3456 std::vector<float> recurrentToCellWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3457 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
3458
3459 std::vector<float> recurrentToOutputWeightsData = GenerateRandomData<float>(tensorInfo20x16.GetNumElements());
3460 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
3461
3462 std::vector<float> cellToInputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3463 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
3464
3465 std::vector<float> cellToForgetWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3466 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
3467
3468 std::vector<float> cellToOutputWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3469 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
3470
3471 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
3472 std::vector<float> projectionWeightsData = GenerateRandomData<float>(tensorInfo16x20.GetNumElements());
3473 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
3474
3475 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
3476 std::vector<float> projectionBiasData(outputSize, 0.f);
3477 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
3478
3479 std::vector<float> inputLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3480 armnn::ConstTensor inputLayerNormWeights(tensorInfo20, forgetGateBiasData);
3481
3482 std::vector<float> forgetLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3483 armnn::ConstTensor forgetLayerNormWeights(tensorInfo20, forgetGateBiasData);
3484
3485 std::vector<float> cellLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3486 armnn::ConstTensor cellLayerNormWeights(tensorInfo20, forgetGateBiasData);
3487
3488 std::vector<float> outLayerNormWeightsData = GenerateRandomData<float>(tensorInfo20.GetNumElements());
3489 armnn::ConstTensor outLayerNormWeights(tensorInfo20, forgetGateBiasData);
3490
3491 armnn::LstmInputParams params;
3492 params.m_InputToForgetWeights = &inputToForgetWeights;
3493 params.m_InputToCellWeights = &inputToCellWeights;
3494 params.m_InputToOutputWeights = &inputToOutputWeights;
3495 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
3496 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
3497 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
3498 params.m_ForgetGateBias = &forgetGateBias;
3499 params.m_CellBias = &cellBias;
3500 params.m_OutputGateBias = &outputGateBias;
3501
3502 // additional params because: descriptor.m_CifgEnabled = false
3503 params.m_InputToInputWeights = &inputToInputWeights;
3504 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
3505 params.m_CellToInputWeights = &cellToInputWeights;
3506 params.m_InputGateBias = &inputGateBias;
3507
3508 // additional params because: descriptor.m_ProjectionEnabled = true
3509 params.m_ProjectionWeights = &projectionWeights;
3510 params.m_ProjectionBias = &projectionBias;
3511
3512 // additional params because: descriptor.m_PeepholeEnabled = true
3513 params.m_CellToForgetWeights = &cellToForgetWeights;
3514 params.m_CellToOutputWeights = &cellToOutputWeights;
3515
3516 // additional params because: despriptor.m_LayerNormEnabled = true
3517 params.m_InputLayerNormWeights = &inputLayerNormWeights;
3518 params.m_ForgetLayerNormWeights = &forgetLayerNormWeights;
3519 params.m_CellLayerNormWeights = &cellLayerNormWeights;
3520 params.m_OutputLayerNormWeights = &outLayerNormWeights;
3521
3522 armnn::INetworkPtr network = armnn::INetwork::Create();
3523 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
3524 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
3525 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
3526 const std::string layerName("lstm");
3527 armnn::IConnectableLayer* const lstmLayer = network->AddLstmLayer(descriptor, params, layerName.c_str());
3528 armnn::IConnectableLayer* const scratchBuffer = network->AddOutputLayer(0);
3529 armnn::IConnectableLayer* const outputStateOut = network->AddOutputLayer(1);
3530 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(2);
3531 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(3);
3532
3533 // connect up
3534 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
3535 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
3536 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
3537 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
3538
3539 inputLayer->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(0));
3540 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
3541
3542 outputStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(1));
3543 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
3544
3545 cellStateIn->GetOutputSlot(0).Connect(lstmLayer->GetInputSlot(2));
3546 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
3547
3548 lstmLayer->GetOutputSlot(0).Connect(scratchBuffer->GetInputSlot(0));
3549 lstmLayer->GetOutputSlot(0).SetTensorInfo(lstmTensorInfoScratchBuff);
3550
3551 lstmLayer->GetOutputSlot(1).Connect(outputStateOut->GetInputSlot(0));
3552 lstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
3553
3554 lstmLayer->GetOutputSlot(2).Connect(cellStateOut->GetInputSlot(0));
3555 lstmLayer->GetOutputSlot(2).SetTensorInfo(cellStateTensorInfo);
3556
3557 lstmLayer->GetOutputSlot(3).Connect(outputLayer->GetInputSlot(0));
3558 lstmLayer->GetOutputSlot(3).SetTensorInfo(outputStateTensorInfo);
3559
3560 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
3561 BOOST_CHECK(deserializedNetwork);
3562
3563 VerifyLstmLayer checker(
3564 layerName,
3565 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
3566 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
3567 descriptor,
3568 params);
3569 deserializedNetwork->Accept(checker);
3570}
3571
3572BOOST_AUTO_TEST_CASE(EnsureLstmLayersBackwardCompatibility)
3573{
3574 // The hex array below is a flat buffer containing a lstm layer with no Cifg, with peephole and projection
3575 // enabled. That array is created before additional layer normalization parameters where added to the
3576 // lstm serializer. That way it can be tested if a lstm model with the old parameter configuration can still be
3577 // loaded
3578 unsigned int size = 10900;
3579 const unsigned char LstmNoCifgWithPeepholeAndProjection_Model[] = {
3580 0x10,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x10,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,
3581 0x0C,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xDC,0x29,0x00,0x00,
3582 0x38,0x29,0x00,0x00,0xB4,0x28,0x00,0x00,0x94,0x01,0x00,0x00,0x3C,0x01,0x00,0x00,0xE0,0x00,0x00,0x00,
3583 0x84,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
3584 0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
3585 0x07,0x00,0x00,0x00,0x70,0xD6,0xFF,0xFF,0x00,0x00,0x00,0x0B,0x04,0x00,0x00,0x00,0x06,0xD7,0xFF,0xFF,
3586 0x04,0x00,0x00,0x00,0x88,0xD7,0xFF,0xFF,0x08,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xF6,0xD6,0xFF,0xFF,
3587 0x07,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
3588 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3589 0xE8,0xD7,0xFF,0xFF,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xC8,0xD6,0xFF,0xFF,0x00,0x00,0x00,0x0B,
3590 0x04,0x00,0x00,0x00,0x5E,0xD7,0xFF,0xFF,0x04,0x00,0x00,0x00,0xE0,0xD7,0xFF,0xFF,0x08,0x00,0x00,0x00,
3591 0x02,0x00,0x00,0x00,0x4E,0xD7,0xFF,0xFF,0x06,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
3592 0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
3593 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xD8,0xFF,0xFF,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
3594 0x20,0xD7,0xFF,0xFF,0x00,0x00,0x00,0x0B,0x04,0x00,0x00,0x00,0xB6,0xD7,0xFF,0xFF,0x04,0x00,0x00,0x00,
3595 0x38,0xD8,0xFF,0xFF,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xA6,0xD7,0xFF,0xFF,0x05,0x00,0x00,0x00,
3596 0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3597 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0xD8,0xFF,0xFF,
3598 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x78,0xD7,0xFF,0xFF,0x00,0x00,0x00,0x0B,0x04,0x00,0x00,0x00,
3599 0x0E,0xD8,0xFF,0xFF,0x04,0x00,0x00,0x00,0x16,0xD8,0xFF,0xFF,0x04,0x00,0x00,0x00,0xFA,0xD7,0xFF,0xFF,
3600 0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
3601 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3602 0xEC,0xD8,0xFF,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0xD8,0xFF,0xFF,0x00,0x00,0x00,0x23,
3603 0x10,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x12,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,
3604 0xE0,0x25,0x00,0x00,0xD0,0x25,0x00,0x00,0x2C,0x00,0x00,0x00,0x00,0x00,0x26,0x00,0x48,0x00,0x04,0x00,
3605 0x08,0x00,0x0C,0x00,0x10,0x00,0x14,0x00,0x18,0x00,0x1C,0x00,0x20,0x00,0x24,0x00,0x28,0x00,0x2C,0x00,
3606 0x30,0x00,0x34,0x00,0x38,0x00,0x3C,0x00,0x40,0x00,0x44,0x00,0x26,0x00,0x00,0x00,0xC4,0x23,0x00,0x00,
3607 0xF8,0x21,0x00,0x00,0x2C,0x20,0x00,0x00,0xF0,0x1A,0x00,0x00,0xB4,0x15,0x00,0x00,0x78,0x10,0x00,0x00,
3608 0xF0,0x0F,0x00,0x00,0x68,0x0F,0x00,0x00,0xE0,0x0E,0x00,0x00,0x14,0x0D,0x00,0x00,0xD8,0x07,0x00,0x00,
3609 0x50,0x07,0x00,0x00,0xC8,0x06,0x00,0x00,0x8C,0x01,0x00,0x00,0x14,0x01,0x00,0x00,0x8C,0x00,0x00,0x00,
3610 0x04,0x00,0x00,0x00,0xEE,0xD7,0xFF,0xFF,0x00,0x00,0x00,0x03,0x64,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
3611 0xFE,0xD8,0xFF,0xFF,0x04,0x00,0x00,0x00,0x14,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,0x00,0x00,
3613 0x00,0x00,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,0x00,0x00,
3615 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5A,0xD8,0xFF,0xFF,0x00,0x00,0x00,0x01,
3616 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x72,0xD8,0xFF,0xFF,
3617 0x00,0x00,0x00,0x03,0x64,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x82,0xD9,0xFF,0xFF,0x04,0x00,0x00,0x00,
3618 0x14,0x00,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,0x00,0x00,
3620 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3621 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3622 0x00,0x00,0x00,0x00,0xDE,0xD8,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3623 0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0xF6,0xD8,0xFF,0xFF,0x00,0x00,0x00,0x03,0x54,0x00,0x00,0x00,
3624 0x04,0x00,0x00,0x00,0x06,0xDA,0xFF,0xFF,0x04,0x00,0x00,0x00,0x10,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,0x00,0x00,
3626 0x00,0x00,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,0x00,0x00,
3628 0x52,0xD9,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
3629 0x10,0x00,0x00,0x00,0x6A,0xD9,0xFF,0xFF,0x00,0x00,0x00,0x03,0x14,0x05,0x00,0x00,0x04,0x00,0x00,0x00,
3630 0x7A,0xDA,0xFF,0xFF,0x04,0x00,0x00,0x00,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3631 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3632 0x00,0x00,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,0x00,0x00,
3634 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3635 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3636 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3637 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3638 0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,
3640 0x00,0x00,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,0x00,0x00,
3642 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3643 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3644 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3645 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3646 0x00,0x00,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,0x00,0x00,
3648 0x00,0x00,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,0x00,0x00,
3650 0x00,0x00,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,0x00,0x00,
3652 0x00,0x00,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,0x00,0x00,
3654 0x00,0x00,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,0x00,0x00,
3656 0x00,0x00,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,0x00,0x00,
3658 0x00,0x00,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,0x00,0x00,
3660 0x00,0x00,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,0x00,0x00,
3662 0x00,0x00,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,0x00,0x00,
3664 0x00,0x00,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,0x00,0x00,
3666 0x00,0x00,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,0x00,0x00,
3668 0x00,0x00,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,0x00,0x00,
3670 0x00,0x00,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,0x00,0x00,
3672 0x00,0x00,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,0x00,0x00,
3674 0x00,0x00,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,0x00,0x00,
3676 0x00,0x00,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,0x00,0x00,
3678 0x00,0x00,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,0x00,0x00,
3680 0x00,0x00,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,0x00,0x00,
3682 0x00,0x00,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,0x00,0x00,
3684 0x00,0x00,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,0x00,0x00,
3686 0x00,0x00,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,0x00,0x00,
3688 0x00,0x00,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,0x00,0x00,
3690 0x00,0x00,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,0x00,0x00,
3692 0x00,0x00,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,0x00,0x00,
3694 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0xDE,0xFF,0xFF,0x00,0x00,0x00,0x01,
3695 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
3696 0xA2,0xDE,0xFF,0xFF,0x00,0x00,0x00,0x03,0x64,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xB2,0xDF,0xFF,0xFF,
3697 0x04,0x00,0x00,0x00,0x14,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,0x00,0x00,
3699 0x00,0x00,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,0x00,0x00,
3701 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0xDF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,
3702 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x26,0xDF,0xFF,0xFF,0x00,0x00,0x00,0x03,
3703 0x64,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x36,0xE0,0xFF,0xFF,0x04,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
3704 0x00,0x00,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,0x00,0x00,
3706 0x00,0x00,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,0x00,0x00,
3708 0x92,0xDF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
3709 0x14,0x00,0x00,0x00,0xAA,0xDF,0xFF,0xFF,0x00,0x00,0x00,0x03,0x14,0x05,0x00,0x00,0x04,0x00,0x00,0x00,
3710 0xBA,0xE0,0xFF,0xFF,0x04,0x00,0x00,0x00,0x40,0x01,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,0x00,0x00,
3712 0x00,0x00,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,0x00,0x00,
3714 0x00,0x00,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,0x00,0x00,
3716 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3717 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3718 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3719 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3720 0x00,0x00,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,0x00,0x00,
3722 0x00,0x00,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,0x00,0x00,
3724 0x00,0x00,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,0x00,0x00,
3726 0x00,0x00,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,0x00,0x00,
3728 0x00,0x00,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,0x00,0x00,
3730 0x00,0x00,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,0x00,0x00,
3732 0x00,0x00,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,0x00,0x00,
3734 0x00,0x00,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,0x00,0x00,
3736 0x00,0x00,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,0x00,0x00,
3738 0x00,0x00,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,0x00,0x00,
3740 0x00,0x00,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,0x00,0x00,
3742 0x00,0x00,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,0x00,0x00,
3744 0x00,0x00,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,0x00,0x00,
3746 0x00,0x00,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,0x00,0x00,
3748 0x00,0x00,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,0x00,0x00,
3750 0x00,0x00,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,0x00,0x00,
3752 0x00,0x00,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,0x00,0x00,
3754 0x00,0x00,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,0x00,0x00,
3756 0x00,0x00,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,0x00,0x00,
3758 0x00,0x00,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,0x00,0x00,
3760 0x00,0x00,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,0x00,0x00,
3762 0x00,0x00,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,0x00,0x00,
3764 0x00,0x00,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,0x00,0x00,
3766 0x00,0x00,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,0x00,0x00,
3768 0x00,0x00,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,0x00,0x00,
3770 0x00,0x00,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,0x00,0x00,
3772 0x00,0x00,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,0x00,0x00,
3774 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0xE4,0xFF,0xFF,0x00,0x00,0x00,0x01,
3775 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
3776 0xE2,0xE4,0xFF,0xFF,0x00,0x00,0x00,0x03,0xA4,0x01,0x00,0x00,0x04,0x00,0x00,0x00,0xF2,0xE5,0xFF,0xFF,
3777 0x04,0x00,0x00,0x00,0x64,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,0x00,0x00,
3779 0x00,0x00,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,0x00,0x00,
3781 0x00,0x00,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,0x00,0x00,
3783 0x00,0x00,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,0x00,0x00,
3785 0x00,0x00,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,0x00,0x00,
3787 0x00,0x00,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,0x00,0x00,
3789 0x00,0x00,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,0x00,0x00,
3791 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3792 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3793 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3794 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3795 0x00,0x00,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,0x00,0x00,
3797 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8E,0xE6,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,
3798 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xAA,0xE6,0xFF,0xFF,
3799 0x00,0x00,0x00,0x03,0x64,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xBA,0xE7,0xFF,0xFF,0x04,0x00,0x00,0x00,
3800 0x14,0x00,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,0x00,0x00,
3802 0x00,0x00,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,0x00,0x00,
3804 0x00,0x00,0x00,0x00,0x16,0xE7,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3805 0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x2E,0xE7,0xFF,0xFF,0x00,0x00,0x00,0x03,0x64,0x00,0x00,0x00,
3806 0x04,0x00,0x00,0x00,0x3E,0xE8,0xFF,0xFF,0x04,0x00,0x00,0x00,0x14,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,0x00,0x00,
3808 0x00,0x00,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,0x00,0x00,
3810 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9A,0xE7,0xFF,0xFF,
3811 0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
3812 0xB2,0xE7,0xFF,0xFF,0x00,0x00,0x00,0x03,0x64,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xC2,0xE8,0xFF,0xFF,
3813 0x04,0x00,0x00,0x00,0x14,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,0x00,0x00,
3815 0x00,0x00,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,0x00,0x00,
3817 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0xE8,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,
3818 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x36,0xE8,0xFF,0xFF,0x00,0x00,0x00,0x03,
3819 0x14,0x05,0x00,0x00,0x04,0x00,0x00,0x00,0x46,0xE9,0xFF,0xFF,0x04,0x00,0x00,0x00,0x40,0x01,0x00,0x00,
3820 0x00,0x00,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,0x00,0x00,
3822 0x00,0x00,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,0x00,0x00,
3824 0x00,0x00,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,0x00,0x00,
3826 0x00,0x00,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,0x00,0x00,
3828 0x00,0x00,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,0x00,0x00,
3830 0x00,0x00,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,0x00,0x00,
3832 0x00,0x00,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,0x00,0x00,
3834 0x00,0x00,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,0x00,0x00,
3836 0x00,0x00,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,0x00,0x00,
3838 0x00,0x00,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,0x00,0x00,
3840 0x00,0x00,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,0x00,0x00,
3842 0x00,0x00,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,0x00,0x00,
3844 0x00,0x00,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,0x00,0x00,
3846 0x00,0x00,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,0x00,0x00,
3848 0x00,0x00,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,0x00,0x00,
3850 0x00,0x00,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,0x00,0x00,
3852 0x00,0x00,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,0x00,0x00,
3854 0x00,0x00,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,0x00,0x00,
3856 0x00,0x00,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,0x00,0x00,
3858 0x00,0x00,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,0x00,0x00,
3860 0x00,0x00,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,0x00,0x00,
3862 0x00,0x00,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,0x00,0x00,
3864 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3865 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3866 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3867 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3868 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3869 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3870 0x00,0x00,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,0x00,0x00,
3872 0x00,0x00,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,0x00,0x00,
3874 0x00,0x00,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,0x00,0x00,
3876 0x00,0x00,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,0x00,0x00,
3878 0x00,0x00,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,0x00,0x00,
3880 0x00,0x00,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,0x00,0x00,
3882 0x00,0x00,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,0x00,0x00,
3884 0x52,0xED,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
3885 0x14,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x6E,0xED,0xFF,0xFF,0x00,0x00,0x00,0x03,0x14,0x05,0x00,0x00,
3886 0x04,0x00,0x00,0x00,0x7E,0xEE,0xFF,0xFF,0x04,0x00,0x00,0x00,0x40,0x01,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,0x00,0x00,
3888 0x00,0x00,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,0x00,0x00,
3890 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3891 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3892 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3893 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3894 0x00,0x00,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,0x00,0x00,
3896 0x00,0x00,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,0x00,0x00,
3898 0x00,0x00,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,0x00,0x00,
3900 0x00,0x00,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,0x00,0x00,
3902 0x00,0x00,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,0x00,0x00,
3904 0x00,0x00,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,0x00,0x00,
3906 0x00,0x00,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,0x00,0x00,
3908 0x00,0x00,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,0x00,0x00,
3910 0x00,0x00,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,0x00,0x00,
3912 0x00,0x00,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,0x00,0x00,
3914 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3915 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3916 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3917 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3918 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3919 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3920 0x00,0x00,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,0x00,0x00,
3922 0x00,0x00,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,0x00,0x00,
3924 0x00,0x00,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,0x00,0x00,
3926 0x00,0x00,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,0x00,0x00,
3928 0x00,0x00,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,0x00,0x00,
3930 0x00,0x00,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,0x00,0x00,
3932 0x00,0x00,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,0x00,0x00,
3934 0x00,0x00,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,0x00,0x00,
3936 0x00,0x00,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,0x00,0x00,
3938 0x00,0x00,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,0x00,0x00,
3940 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3941 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3942 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3943 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3944 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3945 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3946 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3947 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3948 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3949 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3950 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8A,0xF2,0xFF,0xFF,
3951 0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
3952 0x10,0x00,0x00,0x00,0xA6,0xF2,0xFF,0xFF,0x00,0x00,0x00,0x03,0x14,0x05,0x00,0x00,0x04,0x00,0x00,0x00,
3953 0xB6,0xF3,0xFF,0xFF,0x04,0x00,0x00,0x00,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3954 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3955 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3956 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3957 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3958 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3959 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3960 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3961 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3962 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3963 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3964 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3965 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3966 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3967 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3968 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3969 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3970 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3971 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3972 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3973 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3974 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3975 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3976 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3977 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3978 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3979 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3980 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3981 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3982 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3983 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3984 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3985 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3986 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3987 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3988 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3989 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3990 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3991 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3992 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3993 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3994 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3995 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3996 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3997 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3998 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
3999 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4000 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4001 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4002 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4003 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4004 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4005 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4006 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4007 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4008 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4009 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4010 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4011 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4012 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4013 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4014 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4015 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4016 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4017 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2,0xF7,0xFF,0xFF,0x00,0x00,0x00,0x01,
4018 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
4019 0xDE,0xF7,0xFF,0xFF,0x00,0x00,0x00,0x03,0xA4,0x01,0x00,0x00,0x04,0x00,0x00,0x00,0xEE,0xF8,0xFF,0xFF,
4020 0x04,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4021 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4022 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4023 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4024 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4025 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4026 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4027 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4028 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4029 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4030 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4031 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4032 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4033 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4034 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4035 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4036 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4037 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4038 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4039 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4040 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8A,0xF9,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,
4041 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xA6,0xF9,0xFF,0xFF,
4042 0x00,0x00,0x00,0x03,0xA4,0x01,0x00,0x00,0x04,0x00,0x00,0x00,0xB6,0xFA,0xFF,0xFF,0x04,0x00,0x00,0x00,
4043 0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4044 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4045 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4046 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4047 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4048 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4049 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4050 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4051 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4052 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4053 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4054 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4055 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4056 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4057 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4058 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4059 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4060 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4061 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4062 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4063 0x00,0x00,0x00,0x00,0x52,0xFB,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4064 0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x6E,0xFB,0xFF,0xFF,0x00,0x00,0x00,0x03,
4065 0xA4,0x01,0x00,0x00,0x04,0x00,0x00,0x00,0x7E,0xFC,0xFF,0xFF,0x04,0x00,0x00,0x00,0x64,0x00,0x00,0x00,
4066 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4067 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4068 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4069 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4070 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4071 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4072 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4073 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4074 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4075 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4076 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4077 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4078 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4079 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4080 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4081 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4082 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4083 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4084 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4085 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4086 0x1A,0xFD,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4087 0x14,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x10,0x00,0x0C,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x05,0x00,
4088 0x06,0x00,0x07,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x04,0x00,0x00,0x00,0x2E,0xFE,0xFF,0xFF,
4089 0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
4090 0x04,0x00,0x00,0x00,0x6C,0x73,0x74,0x6D,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xEC,0x00,0x00,0x00,
4091 0xD0,0x00,0x00,0x00,0xB4,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0x5C,0x00,0x00,0x00,
4092 0x30,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x14,0xFF,0xFF,0xFF,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
4093 0xA6,0xFD,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4094 0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x3C,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
4095 0xCE,0xFD,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4096 0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x64,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
4097 0xF6,0xFD,0xFF,0xFF,0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4098 0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0xB4,0xFE,0xFF,0xFF,0x04,0x00,0x00,0x00,0x1A,0xFE,0xFF,0xFF,
4099 0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4100 0x50,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4101 0x08,0x00,0x10,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4102 0x00,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4103 0x00,0x00,0x00,0x00,0xE8,0xFE,0xFF,0xFF,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x00,0x7E,0xFF,0xFF,0xFF,
4104 0x0C,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
4105 0x02,0x00,0x00,0x00,0x76,0xFF,0xFF,0xFF,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
4106 0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
4107 0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x68,0xFF,0xFF,0xFF,0x04,0x00,0x00,0x00,0xCE,0xFE,0xFF,0xFF,
4108 0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4109 0x10,0x00,0x00,0x00,0x08,0x00,0x0E,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x09,
4110 0x0C,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x08,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,
4111 0x08,0x00,0x0E,0x00,0x04,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
4112 0x00,0x00,0x0E,0x00,0x18,0x00,0x04,0x00,0x08,0x00,0x0C,0x00,0x10,0x00,0x14,0x00,0x0E,0x00,0x00,0x00,
4113 0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
4114 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,
4115 0x08,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6E,0xFF,0xFF,0xFF,
4116 0x00,0x00,0x00,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
4117 0x14,0x00,0x00,0x00,0x08,0x00,0x0C,0x00,0x07,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x09,
4118 0x04,0x00,0x00,0x00,0xF6,0xFF,0xFF,0xFF,0x0C,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x0A,0x00,0x04,0x00,
4119 0x06,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x14,0x00,0x00,0x00,0x04,0x00,0x08,0x00,
4120 0x0C,0x00,0x10,0x00,0x0E,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
4121 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
4122 0x0C,0x00,0x00,0x00,0x08,0x00,0x0A,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
4123 0x00,0x00,0x0A,0x00,0x10,0x00,0x08,0x00,0x07,0x00,0x0C,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
4124 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0 };
4125
4126 std::stringstream ss;
4127 for (unsigned int i = 0; i < size; ++i)
4128 {
4129 ss << LstmNoCifgWithPeepholeAndProjection_Model[i];
4130 }
4131 std::string lstmLayerNetwork = ss.str();
4132 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(lstmLayerNetwork);
4133 BOOST_CHECK(deserializedNetwork);
4134
4135 // generating the same model parameters which where used to serialize the model (Layer norm is not specified)
4136 armnn::LstmDescriptor descriptor;
4137 descriptor.m_ActivationFunc = 4;
4138 descriptor.m_ClippingThresProj = 0.0f;
4139 descriptor.m_ClippingThresCell = 0.0f;
4140 descriptor.m_CifgEnabled = false;
4141 descriptor.m_ProjectionEnabled = true;
4142 descriptor.m_PeepholeEnabled = true;
4143
4144 const uint32_t batchSize = 2;
4145 const uint32_t inputSize = 5;
4146 const uint32_t numUnits = 20;
4147 const uint32_t outputSize = 16;
4148
4149 armnn::TensorInfo tensorInfo20x5({numUnits, inputSize}, armnn::DataType::Float32);
4150 std::vector<float> inputToInputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4151 armnn::ConstTensor inputToInputWeights(tensorInfo20x5, inputToInputWeightsData);
4152
4153 std::vector<float> inputToForgetWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4154 armnn::ConstTensor inputToForgetWeights(tensorInfo20x5, inputToForgetWeightsData);
4155
4156 std::vector<float> inputToCellWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4157 armnn::ConstTensor inputToCellWeights(tensorInfo20x5, inputToCellWeightsData);
4158
4159 std::vector<float> inputToOutputWeightsData(tensorInfo20x5.GetNumElements(), 0.0f);
4160 armnn::ConstTensor inputToOutputWeights(tensorInfo20x5, inputToOutputWeightsData);
4161
4162 armnn::TensorInfo tensorInfo20({numUnits}, armnn::DataType::Float32);
4163 std::vector<float> inputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4164 armnn::ConstTensor inputGateBias(tensorInfo20, inputGateBiasData);
4165
4166 std::vector<float> forgetGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4167 armnn::ConstTensor forgetGateBias(tensorInfo20, forgetGateBiasData);
4168
4169 std::vector<float> cellBiasData(tensorInfo20.GetNumElements(), 0.0f);
4170 armnn::ConstTensor cellBias(tensorInfo20, cellBiasData);
4171
4172 std::vector<float> outputGateBiasData(tensorInfo20.GetNumElements(), 0.0f);
4173 armnn::ConstTensor outputGateBias(tensorInfo20, outputGateBiasData);
4174
4175 armnn::TensorInfo tensorInfo20x16({numUnits, outputSize}, armnn::DataType::Float32);
4176 std::vector<float> recurrentToInputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4177 armnn::ConstTensor recurrentToInputWeights(tensorInfo20x16, recurrentToInputWeightsData);
4178
4179 std::vector<float> recurrentToForgetWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4180 armnn::ConstTensor recurrentToForgetWeights(tensorInfo20x16, recurrentToForgetWeightsData);
4181
4182 std::vector<float> recurrentToCellWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4183 armnn::ConstTensor recurrentToCellWeights(tensorInfo20x16, recurrentToCellWeightsData);
4184
4185 std::vector<float> recurrentToOutputWeightsData(tensorInfo20x16.GetNumElements(), 0.0f);
4186 armnn::ConstTensor recurrentToOutputWeights(tensorInfo20x16, recurrentToOutputWeightsData);
4187
4188 std::vector<float> cellToInputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4189 armnn::ConstTensor cellToInputWeights(tensorInfo20, cellToInputWeightsData);
4190
4191 std::vector<float> cellToForgetWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4192 armnn::ConstTensor cellToForgetWeights(tensorInfo20, cellToForgetWeightsData);
4193
4194 std::vector<float> cellToOutputWeightsData(tensorInfo20.GetNumElements(), 0.0f);
4195 armnn::ConstTensor cellToOutputWeights(tensorInfo20, cellToOutputWeightsData);
4196
4197 armnn::TensorInfo tensorInfo16x20({outputSize, numUnits}, armnn::DataType::Float32);
4198 std::vector<float> projectionWeightsData(tensorInfo16x20.GetNumElements(), 0.0f);
4199 armnn::ConstTensor projectionWeights(tensorInfo16x20, projectionWeightsData);
4200
4201 armnn::TensorInfo tensorInfo16({outputSize}, armnn::DataType::Float32);
4202 std::vector<float> projectionBiasData(outputSize, 0.0f);
4203 armnn::ConstTensor projectionBias(tensorInfo16, projectionBiasData);
4204
4205 armnn::LstmInputParams params;
4206 params.m_InputToForgetWeights = &inputToForgetWeights;
4207 params.m_InputToCellWeights = &inputToCellWeights;
4208 params.m_InputToOutputWeights = &inputToOutputWeights;
4209 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4210 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4211 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4212 params.m_ForgetGateBias = &forgetGateBias;
4213 params.m_CellBias = &cellBias;
4214 params.m_OutputGateBias = &outputGateBias;
4215
4216 // additional params because: descriptor.m_CifgEnabled = false
4217 params.m_InputToInputWeights = &inputToInputWeights;
4218 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4219 params.m_CellToInputWeights = &cellToInputWeights;
4220 params.m_InputGateBias = &inputGateBias;
4221
4222 // additional params because: descriptor.m_ProjectionEnabled = true
4223 params.m_ProjectionWeights = &projectionWeights;
4224 params.m_ProjectionBias = &projectionBias;
4225
4226 // additional params because: descriptor.m_PeepholeEnabled = true
4227 params.m_CellToForgetWeights = &cellToForgetWeights;
4228 params.m_CellToOutputWeights = &cellToOutputWeights;
4229
4230 const std::string layerName("lstm");
4231 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::Float32);
4232 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Float32);
4233 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::Float32);
4234 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * 4 }, armnn::DataType::Float32);
4235
4236 // lets verify that the deserialized model without the new layer normalization parameters still works
4237 VerifyLstmLayer checker(
4238 layerName,
4239 {inputTensorInfo, outputStateTensorInfo, cellStateTensorInfo},
4240 {lstmTensorInfoScratchBuff, outputStateTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4241 descriptor,
4242 params);
4243 deserializedNetwork->Accept(checker);
4244}
4245
Jan Eilers5b01a892019-07-23 09:47:43 +01004246class VerifyQuantizedLstmLayer : public LayerVerifierBase
4247{
4248
4249public:
4250 VerifyQuantizedLstmLayer(const std::string& layerName,
4251 const std::vector<armnn::TensorInfo>& inputInfos,
4252 const std::vector<armnn::TensorInfo>& outputInfos,
4253 const armnn::QuantizedLstmInputParams& inputParams) :
4254 LayerVerifierBase(layerName, inputInfos, outputInfos), m_InputParams(inputParams)
4255 {
4256 }
4257
4258 void VisitQuantizedLstmLayer(const armnn::IConnectableLayer* layer,
4259 const armnn::QuantizedLstmInputParams& params,
4260 const char* name)
4261 {
4262 VerifyNameAndConnections(layer, name);
4263 VerifyInputParameters(params);
4264 }
4265
4266protected:
4267 void VerifyInputParameters(const armnn::QuantizedLstmInputParams& params)
4268 {
4269 VerifyConstTensors("m_InputToInputWeights",
4270 m_InputParams.m_InputToInputWeights, params.m_InputToInputWeights);
4271 VerifyConstTensors("m_InputToForgetWeights",
4272 m_InputParams.m_InputToForgetWeights, params.m_InputToForgetWeights);
4273 VerifyConstTensors("m_InputToCellWeights",
4274 m_InputParams.m_InputToCellWeights, params.m_InputToCellWeights);
4275 VerifyConstTensors("m_InputToOutputWeights",
4276 m_InputParams.m_InputToOutputWeights, params.m_InputToOutputWeights);
4277 VerifyConstTensors("m_RecurrentToInputWeights",
4278 m_InputParams.m_RecurrentToInputWeights, params.m_RecurrentToInputWeights);
4279 VerifyConstTensors("m_RecurrentToForgetWeights",
4280 m_InputParams.m_RecurrentToForgetWeights, params.m_RecurrentToForgetWeights);
4281 VerifyConstTensors("m_RecurrentToCellWeights",
4282 m_InputParams.m_RecurrentToCellWeights, params.m_RecurrentToCellWeights);
4283 VerifyConstTensors("m_RecurrentToOutputWeights",
4284 m_InputParams.m_RecurrentToOutputWeights, params.m_RecurrentToOutputWeights);
4285 VerifyConstTensors("m_InputGateBias",
4286 m_InputParams.m_InputGateBias, params.m_InputGateBias);
4287 VerifyConstTensors("m_ForgetGateBias",
4288 m_InputParams.m_ForgetGateBias, params.m_ForgetGateBias);
4289 VerifyConstTensors("m_CellBias",
4290 m_InputParams.m_CellBias, params.m_CellBias);
4291 VerifyConstTensors("m_OutputGateBias",
4292 m_InputParams.m_OutputGateBias, params.m_OutputGateBias);
4293 }
4294
4295private:
4296 armnn::QuantizedLstmInputParams m_InputParams;
4297};
4298
4299BOOST_AUTO_TEST_CASE(SerializeDeserializeQuantizedLstm)
4300{
4301 const uint32_t batchSize = 1;
4302 const uint32_t inputSize = 2;
4303 const uint32_t numUnits = 4;
4304 const uint32_t outputSize = numUnits;
4305
4306 std::vector<uint8_t> inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4307 std::vector<unsigned int> inputToInputWeightsDimensions = {1, 1, 3, 3};
4308 armnn::ConstTensor inputToInputWeights(armnn::TensorInfo(
4309 4, inputToInputWeightsDimensions.data(),
4310 armnn::DataType::QuantisedAsymm8), inputToInputWeightsData);
4311
4312 std::vector<uint8_t> inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4313 std::vector<unsigned int> inputToForgetWeightsDimensions = {1, 1, 3, 3};
4314 armnn::ConstTensor inputToForgetWeights(armnn::TensorInfo(
4315 4, inputToForgetWeightsDimensions.data(),
4316 armnn::DataType::QuantisedAsymm8), inputToForgetWeightsData);
4317
4318 std::vector<uint8_t> inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4319 std::vector<unsigned int> inputToCellWeightsDimensions = {1, 1, 3, 3};
4320 armnn::ConstTensor inputToCellWeights(armnn::TensorInfo(
4321 4, inputToCellWeightsDimensions.data(),
4322 armnn::DataType::QuantisedAsymm8), inputToCellWeightsData);
4323
4324 std::vector<uint8_t> inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4325 std::vector<unsigned int> inputToOutputWeightsDimensions = {1, 1, 3, 3};
4326 armnn::ConstTensor inputToOutputWeights(armnn::TensorInfo(
4327 4, inputToOutputWeightsDimensions.data(),
4328 armnn::DataType::QuantisedAsymm8), inputToOutputWeightsData);
4329
4330 std::vector<uint8_t> recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4331 std::vector<unsigned int> recurrentToInputWeightsDimensions = {1, 1, 3, 3};
4332 armnn::ConstTensor recurrentToInputWeights(armnn::TensorInfo(
4333 4, recurrentToInputWeightsDimensions.data(),
4334 armnn::DataType::QuantisedAsymm8), recurrentToInputWeightsData);
4335
4336 std::vector<uint8_t> recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4337 std::vector<unsigned int> recurrentToForgetWeightsDimensions = {1, 1, 3, 3};
4338 armnn::ConstTensor recurrentToForgetWeights(armnn::TensorInfo(
4339 4, recurrentToForgetWeightsDimensions.data(),
4340 armnn::DataType::QuantisedAsymm8), recurrentToForgetWeightsData);
4341
4342 std::vector<uint8_t> recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4343 std::vector<unsigned int> recurrentToCellWeightsDimensions = {1, 1, 3, 3};
4344 armnn::ConstTensor recurrentToCellWeights(armnn::TensorInfo(
4345 4, recurrentToCellWeightsDimensions.data(),
4346 armnn::DataType::QuantisedAsymm8), recurrentToCellWeightsData);
4347
4348 std::vector<uint8_t> recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4349 std::vector<unsigned int> recurrentToOutputWeightsDimensions = {1, 1, 3, 3};
4350 armnn::ConstTensor recurrentToOutputWeights(armnn::TensorInfo(
4351 4, recurrentToOutputWeightsDimensions.data(),
4352 armnn::DataType::QuantisedAsymm8), recurrentToOutputWeightsData);
4353
4354
4355 std::vector<int32_t> inputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4356 std::vector<unsigned int> inputGateBiasDimensions = {1, 1, 3, 3};
4357 armnn::ConstTensor inputGateBias(armnn::TensorInfo(
4358 4, inputGateBiasDimensions.data(),
4359 armnn::DataType::Signed32), inputGateBiasData);
4360
4361 std::vector<int32_t> forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4362 std::vector<unsigned int> forgetGateBiasDimensions = {1, 1, 3, 3};
4363 armnn::ConstTensor forgetGateBias(armnn::TensorInfo(
4364 4, forgetGateBiasDimensions.data(),
4365 armnn::DataType::Signed32), forgetGateBiasData);
4366
4367 std::vector<int32_t> cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4368 std::vector<unsigned int> cellBiasDimensions = {1, 1, 3, 3};
4369 armnn::ConstTensor cellBias(armnn::TensorInfo(
4370 4, cellBiasDimensions.data(),
4371 armnn::DataType::Signed32), cellBiasData);
4372
4373 std::vector<int32_t> outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
4374 std::vector<unsigned int> outputGateBiasDimensions = {1, 1, 3, 3};
4375 armnn::ConstTensor outputGateBias(armnn::TensorInfo(
4376 4, outputGateBiasDimensions.data(),
4377 armnn::DataType::Signed32), outputGateBiasData);
4378
4379 armnn::QuantizedLstmInputParams params;
4380 params.m_InputToInputWeights = &inputToInputWeights;
4381 params.m_InputToForgetWeights = &inputToForgetWeights;
4382 params.m_InputToCellWeights = &inputToCellWeights;
4383 params.m_InputToOutputWeights = &inputToOutputWeights;
4384 params.m_RecurrentToInputWeights = &recurrentToInputWeights;
4385 params.m_RecurrentToForgetWeights = &recurrentToForgetWeights;
4386 params.m_RecurrentToCellWeights = &recurrentToCellWeights;
4387 params.m_RecurrentToOutputWeights = &recurrentToOutputWeights;
4388 params.m_InputGateBias = &inputGateBias;
4389 params.m_ForgetGateBias = &forgetGateBias;
4390 params.m_CellBias = &cellBias;
4391 params.m_OutputGateBias = &outputGateBias;
4392
4393 armnn::INetworkPtr network = armnn::INetwork::Create();
4394 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
4395 armnn::IConnectableLayer* const cellStateIn = network->AddInputLayer(1);
4396 armnn::IConnectableLayer* const outputStateIn = network->AddInputLayer(2);
4397 const std::string layerName("QuantizedLstm");
4398 armnn::IConnectableLayer* const quantizedLstmLayer = network->AddQuantizedLstmLayer(params, layerName.c_str());
4399 armnn::IConnectableLayer* const cellStateOut = network->AddOutputLayer(0);
4400 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(1);
4401
4402 // connect up
4403 armnn::TensorInfo inputTensorInfo({ batchSize, inputSize }, armnn::DataType::QuantisedAsymm8);
4404 armnn::TensorInfo cellStateTensorInfo({ batchSize, numUnits}, armnn::DataType::Signed32);
4405 armnn::TensorInfo outputStateTensorInfo({ batchSize, outputSize }, armnn::DataType::QuantisedAsymm8);
4406
4407 inputLayer->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(0));
4408 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
4409
4410 cellStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(1));
4411 cellStateIn->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4412
4413 outputStateIn->GetOutputSlot(0).Connect(quantizedLstmLayer->GetInputSlot(2));
4414 outputStateIn->GetOutputSlot(0).SetTensorInfo(outputStateTensorInfo);
4415
4416 quantizedLstmLayer->GetOutputSlot(0).Connect(cellStateOut->GetInputSlot(0));
4417 quantizedLstmLayer->GetOutputSlot(0).SetTensorInfo(cellStateTensorInfo);
4418
4419 quantizedLstmLayer->GetOutputSlot(1).Connect(outputLayer->GetInputSlot(0));
4420 quantizedLstmLayer->GetOutputSlot(1).SetTensorInfo(outputStateTensorInfo);
4421
4422 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
4423 BOOST_CHECK(deserializedNetwork);
4424
4425 VerifyQuantizedLstmLayer checker(
4426 layerName,
4427 {inputTensorInfo, cellStateTensorInfo, outputStateTensorInfo},
4428 {cellStateTensorInfo, outputStateTensorInfo},
4429 params);
4430
4431 deserializedNetwork->Accept(checker);
4432}
4433
Nattapat Chaimanowong30b00202019-02-20 17:31:34 +00004434BOOST_AUTO_TEST_SUITE_END()