blob: c4c6eedb20217dcc0920294afa20b6780b3f7f49 [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
6#include <armnn/ArmNN.hpp>
7#include <armnn/INetwork.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +00008
Mike Kelly8c1701a2019-02-11 17:01:27 +00009#include "../Serializer.hpp"
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000010
Derek Lamberti0028d1b2019-02-20 13:57:42 +000011#include <armnnDeserializer/IDeserializer.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000012
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +000013#include <random>
Mike Kelly8c1701a2019-02-11 17:01:27 +000014#include <sstream>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000015#include <vector>
16
Mike Kelly8c1701a2019-02-11 17:01:27 +000017#include <boost/test/unit_test.hpp>
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +000018#include <flatbuffers/idl.h>
19
Derek Lamberti0028d1b2019-02-20 13:57:42 +000020using armnnDeserializer::IDeserializer;
Mike Kelly8c1701a2019-02-11 17:01:27 +000021
Saoirse Stewart3166c3e2019-02-18 15:24:53 +000022namespace
23{
24
25armnn::INetworkPtr DeserializeNetwork(const std::string& serializerString)
26{
27 std::vector<std::uint8_t> const serializerVector{serializerString.begin(), serializerString.end()};
Derek Lamberti0028d1b2019-02-20 13:57:42 +000028 return IDeserializer::Create()->CreateNetworkFromBinary(serializerVector);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +000029}
30
31std::string SerializeNetwork(const armnn::INetwork& network)
32{
33 armnnSerializer::Serializer serializer;
34 serializer.Serialize(network);
35
36 std::stringstream stream;
37 serializer.SaveSerializedToStream(stream);
38
39 std::string serializerString{stream.str()};
40 return serializerString;
41}
42
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +000043template<typename DataType>
44static std::vector<DataType> GenerateRandomData(size_t size)
45{
46 constexpr bool isIntegerType = std::is_integral<DataType>::value;
47 using Distribution =
48 typename std::conditional<isIntegerType,
49 std::uniform_int_distribution<DataType>,
50 std::uniform_real_distribution<DataType>>::type;
51
52 static constexpr DataType lowerLimit = std::numeric_limits<DataType>::min();
53 static constexpr DataType upperLimit = std::numeric_limits<DataType>::max();
54
55 static Distribution distribution(lowerLimit, upperLimit);
56 static std::default_random_engine generator;
57
58 std::vector<DataType> randomData(size);
59 std::generate(randomData.begin(), randomData.end(), []() { return distribution(generator); });
60
61 return randomData;
62}
63
64void CheckDeserializedNetworkAgainstOriginal(const armnn::INetwork& deserializedNetwork,
65 const armnn::INetwork& originalNetwork,
66 const armnn::TensorShape& inputShape,
67 const armnn::TensorShape& outputShape,
68 armnn::LayerBindingId inputBindingId = 0,
69 armnn::LayerBindingId outputBindingId = 0)
70{
71 armnn::IRuntime::CreationOptions options;
72 armnn::IRuntimePtr runtime = armnn::IRuntime::Create(options);
73
74 std::vector<armnn::BackendId> preferredBackends = { armnn::BackendId("CpuRef") };
75
76 // Optimize original network
77 armnn::IOptimizedNetworkPtr optimizedOriginalNetwork =
78 armnn::Optimize(originalNetwork, preferredBackends, runtime->GetDeviceSpec());
79 BOOST_CHECK(optimizedOriginalNetwork);
80
81 // Optimize deserialized network
82 armnn::IOptimizedNetworkPtr optimizedDeserializedNetwork =
83 armnn::Optimize(deserializedNetwork, preferredBackends, runtime->GetDeviceSpec());
84 BOOST_CHECK(optimizedDeserializedNetwork);
85
86 armnn::NetworkId networkId1;
87 armnn::NetworkId networkId2;
88
89 // Load original and deserialized network
90 armnn::Status status1 = runtime->LoadNetwork(networkId1, std::move(optimizedOriginalNetwork));
91 BOOST_CHECK(status1 == armnn::Status::Success);
92
93 armnn::Status status2 = runtime->LoadNetwork(networkId2, std::move(optimizedDeserializedNetwork));
94 BOOST_CHECK(status2 == armnn::Status::Success);
95
96 // Generate some input data
97 std::vector<float> inputData = GenerateRandomData<float>(inputShape.GetNumElements());
98
99 armnn::InputTensors inputTensors1
100 {
101 { 0, armnn::ConstTensor(runtime->GetInputTensorInfo(networkId1, inputBindingId), inputData.data()) }
102 };
103
104 armnn::InputTensors inputTensors2
105 {
106 { 0, armnn::ConstTensor(runtime->GetInputTensorInfo(networkId2, inputBindingId), inputData.data()) }
107 };
108
109 std::vector<float> outputData1(outputShape.GetNumElements());
110 std::vector<float> outputData2(outputShape.GetNumElements());
111
112 armnn::OutputTensors outputTensors1
113 {
114 { 0, armnn::Tensor(runtime->GetOutputTensorInfo(networkId1, outputBindingId), outputData1.data()) }
115 };
116
117 armnn::OutputTensors outputTensors2
118 {
119 { 0, armnn::Tensor(runtime->GetOutputTensorInfo(networkId2, outputBindingId), outputData2.data()) }
120 };
121
122 // Run original and deserialized network
123 runtime->EnqueueWorkload(networkId1, inputTensors1, outputTensors1);
124 runtime->EnqueueWorkload(networkId2, inputTensors2, outputTensors2);
125
126 // Compare output data
127 BOOST_CHECK_EQUAL_COLLECTIONS(outputData1.begin(), outputData1.end(),
128 outputData2.begin(), outputData2.end());
129}
130
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000131} // anonymous namespace
132
133BOOST_AUTO_TEST_SUITE(SerializerTests)
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000134
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000135BOOST_AUTO_TEST_CASE(SerializeAddition)
Mike Kelly8c1701a2019-02-11 17:01:27 +0000136{
137 armnn::INetworkPtr network = armnn::INetwork::Create();
138 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
139 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
140
141 armnn::IConnectableLayer* const additionLayer0 = network->AddAdditionLayer();
142 inputLayer0->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(0));
143 inputLayer1->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(1));
144
145 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
146 additionLayer0->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
147
148 armnnSerializer::Serializer serializer;
149 serializer.Serialize(*network);
150
151 std::stringstream stream;
152 serializer.SaveSerializedToStream(stream);
153 BOOST_TEST(stream.str().length() > 0);
154}
155
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000156BOOST_AUTO_TEST_CASE(SerializeMultiplication)
Sadik Armagan5f450272019-02-12 14:31:45 +0000157{
158 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
159
160 armnn::INetworkPtr network = armnn::INetwork::Create();
161 armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
162 armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
163
164 const char* multLayerName = "mult_0";
165
166 armnn::IConnectableLayer* const multiplicationLayer0 = network->AddMultiplicationLayer(multLayerName);
167 inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer0->GetInputSlot(0));
168 inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer0->GetInputSlot(1));
169
170 armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
171 multiplicationLayer0->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
172
173 armnnSerializer::Serializer serializer;
174 serializer.Serialize(*network);
175
176 std::stringstream stream;
177 serializer.SaveSerializedToStream(stream);
178 BOOST_TEST(stream.str().length() > 0);
179 BOOST_TEST(stream.str().find(multLayerName) != stream.str().npos);
180}
181
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000182BOOST_AUTO_TEST_CASE(SerializeDeserializeConvolution2d)
Saoirse Stewart263829c2019-02-19 15:54:14 +0000183{
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000184 armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
185 armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
Saoirse Stewart263829c2019-02-19 15:54:14 +0000186
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000187 armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
188 armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32);
189
190 // Construct network
191 armnn::INetworkPtr network = armnn::INetwork::Create();
192
193 armnn::Convolution2dDescriptor descriptor;
194 descriptor.m_PadLeft = 1;
195 descriptor.m_PadRight = 1;
196 descriptor.m_PadTop = 1;
197 descriptor.m_PadBottom = 1;
198 descriptor.m_StrideX = 2;
199 descriptor.m_StrideY = 2;
200 descriptor.m_BiasEnabled = true;
201 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
202
203 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
204 armnn::ConstTensor weights(weightsInfo, weightsData);
205
206 std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
207 armnn::ConstTensor biases(biasesInfo, biasesData);
208
209 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0, "input");
210 armnn::IConnectableLayer* const convLayer =
211 network->AddConvolution2dLayer(descriptor, weights, biases, "convolution");
212 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0, "output");
213
214 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
215 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
216
217 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
218 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
219
220 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
221 BOOST_CHECK(deserializedNetwork);
222
223 CheckDeserializedNetworkAgainstOriginal(*network,
224 *deserializedNetwork,
225 inputInfo.GetShape(),
226 outputInfo.GetShape());
227}
228
229BOOST_AUTO_TEST_CASE(SerializeDeserializeReshape)
230{
231 unsigned int inputShape[] = { 1, 9 };
232 unsigned int outputShape[] = { 3, 3 };
Saoirse Stewart263829c2019-02-19 15:54:14 +0000233
234 auto inputTensorInfo = armnn::TensorInfo(2, inputShape, armnn::DataType::Float32);
235 auto outputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32);
236 auto reshapeOutputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32);
237
238 armnn::ReshapeDescriptor reshapeDescriptor;
239 reshapeDescriptor.m_TargetShape = reshapeOutputTensorInfo.GetShape();
240
241 armnn::INetworkPtr network = armnn::INetwork::Create();
242 armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
243 armnn::IConnectableLayer *const reshapeLayer = network->AddReshapeLayer(reshapeDescriptor, "ReshapeLayer");
244 armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
245
246 inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0));
247 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
248 reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
249 reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
250
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000251 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
252 BOOST_CHECK(deserializedNetwork);
Saoirse Stewart263829c2019-02-19 15:54:14 +0000253
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000254 CheckDeserializedNetworkAgainstOriginal(*network,
255 *deserializedNetwork,
256 inputTensorInfo.GetShape(),
257 outputTensorInfo.GetShape());
Saoirse Stewart263829c2019-02-19 15:54:14 +0000258}
259
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000260BOOST_AUTO_TEST_CASE(SerializeDeserializeDepthwiseConvolution2d)
261{
262 armnn::TensorInfo inputInfo ({ 1, 5, 5, 3 }, armnn::DataType::Float32);
263 armnn::TensorInfo outputInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
264
265 armnn::TensorInfo weightsInfo({ 1, 3, 3, 3 }, armnn::DataType::Float32);
266 armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
267
268 armnn::DepthwiseConvolution2dDescriptor descriptor;
269 descriptor.m_StrideX = 1;
270 descriptor.m_StrideY = 1;
271 descriptor.m_BiasEnabled = true;
272 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
273
274 std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
275 armnn::ConstTensor weights(weightsInfo, weightsData);
276
277 std::vector<int32_t> biasesData = GenerateRandomData<int32_t>(biasesInfo.GetNumElements());
278 armnn::ConstTensor biases(biasesInfo, biasesData);
279
280 armnn::INetworkPtr network = armnn::INetwork::Create();
281 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
282 armnn::IConnectableLayer* const depthwiseConvLayer =
283 network->AddDepthwiseConvolution2dLayer(descriptor, weights, biases, "depthwiseConv");
284 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
285
286 inputLayer->GetOutputSlot(0).Connect(depthwiseConvLayer->GetInputSlot(0));
287 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
288 depthwiseConvLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
289 depthwiseConvLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
290
291 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
292 BOOST_CHECK(deserializedNetwork);
293
294 CheckDeserializedNetworkAgainstOriginal(*network,
295 *deserializedNetwork,
296 inputInfo.GetShape(),
297 outputInfo.GetShape());
298}
299
300BOOST_AUTO_TEST_CASE(SerializeDeserializeSoftmax)
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000301{
302 armnn::TensorInfo tensorInfo({1, 10}, armnn::DataType::Float32);
303
304 armnn::SoftmaxDescriptor descriptor;
305 descriptor.m_Beta = 1.0f;
306
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000307 armnn::INetworkPtr network = armnn::INetwork::Create();
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000308 armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
309 armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, "softmax");
310 armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000311
312 inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
313 inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
314 softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
315 softmaxLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
316
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000317 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000318 BOOST_CHECK(deserializedNetwork);
319
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000320 CheckDeserializedNetworkAgainstOriginal(*network,
321 *deserializedNetwork,
322 tensorInfo.GetShape(),
323 tensorInfo.GetShape());
Aron Virginas-Tarfc413c02019-02-13 15:41:52 +0000324}
325
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000326BOOST_AUTO_TEST_CASE(SerializeDeserializePooling2d)
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000327{
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000328 unsigned int inputShape[] = {1, 2, 2, 1};
329 unsigned int outputShape[] = {1, 1, 1, 1};
330
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000331 auto inputInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
332 auto outputInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000333
334 armnn::Pooling2dDescriptor desc;
335 desc.m_DataLayout = armnn::DataLayout::NHWC;
336 desc.m_PadTop = 0;
337 desc.m_PadBottom = 0;
338 desc.m_PadLeft = 0;
339 desc.m_PadRight = 0;
340 desc.m_PoolType = armnn::PoolingAlgorithm::Average;
341 desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
342 desc.m_PaddingMethod = armnn::PaddingMethod::Exclude;
343 desc.m_PoolHeight = 2;
344 desc.m_PoolWidth = 2;
345 desc.m_StrideX = 2;
346 desc.m_StrideY = 2;
347
348 armnn::INetworkPtr network = armnn::INetwork::Create();
349 armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
350 armnn::IConnectableLayer *const pooling2dLayer = network->AddPooling2dLayer(desc, "ReshapeLayer");
351 armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
352
353 inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000354 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000355 pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000356 pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000357
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000358 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
359 BOOST_CHECK(deserializedNetwork);
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000360
Aron Virginas-Tarc04125f2019-02-19 16:31:08 +0000361 CheckDeserializedNetworkAgainstOriginal(*network,
362 *deserializedNetwork,
363 inputInfo.GetShape(),
364 outputInfo.GetShape());
Saoirse Stewart3166c3e2019-02-18 15:24:53 +0000365}
366
Nattapat Chaimanowong30b00202019-02-20 17:31:34 +0000367BOOST_AUTO_TEST_CASE(SerializeDeserializePermute)
368{
369 unsigned int inputShape[] = { 4, 3, 2, 1 };
370 unsigned int outputShape[] = { 1, 2, 3, 4 };
371 unsigned int dimsMapping[] = { 3, 2, 1, 0 };
372
373 auto inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
374 auto outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
375
376 armnn::PermuteDescriptor permuteDescriptor(armnn::PermutationVector(dimsMapping, 4));
377
378 armnn::INetworkPtr network = armnn::INetwork::Create();
379 armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0);
380 armnn::IConnectableLayer *const permuteLayer = network->AddPermuteLayer(permuteDescriptor, "PermuteLayer");
381 armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0);
382
383 inputLayer->GetOutputSlot(0).Connect(permuteLayer->GetInputSlot(0));
384 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
385 permuteLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
386 permuteLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
387
388 armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
389 BOOST_CHECK(deserializedNetwork);
390
391 CheckDeserializedNetworkAgainstOriginal(*network,
392 *deserializedNetwork,
393 inputTensorInfo.GetShape(),
394 outputTensorInfo.GetShape());
395}
396
397BOOST_AUTO_TEST_SUITE_END()