2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
7 #include <boost/test/unit_test.hpp>
9 #include <boost/cast.hpp>
11 #include <backends/WorkloadData.hpp>
12 #include <backends/WorkloadFactory.hpp>
13 #include <backends/CpuTensorHandle.hpp>
20 using namespace armnn;
27 // Calls CreateWorkload for a layer, and checks the returned pointer is of the correct type.
28 template<typename Workload>
29 std::unique_ptr<Workload> MakeAndCheckWorkload(Layer& layer, Graph& graph, const IWorkloadFactory& factory)
31 std::unique_ptr<IWorkload> workload = layer.CreateWorkload(graph, factory);
32 BOOST_TEST(workload.get() == boost::polymorphic_downcast<Workload*>(workload.get()),
33 "Cannot convert to derived class");
34 std::string reasonIfUnsupported;
35 layer.SetBackendId(factory.GetBackendId());
36 BOOST_TEST(factory.IsLayerSupported(layer, layer.GetDataType(), reasonIfUnsupported));
37 return std::unique_ptr<Workload>(static_cast<Workload*>(workload.release()));
40 // Connects two layers.
41 void Connect(Layer* from, Layer* to, const TensorInfo& tensorInfo, unsigned int fromIndex = 0, unsigned int toIndex = 0)
43 from->GetOutputSlot(fromIndex).Connect(to->GetInputSlot(toIndex));
44 from->GetOutputHandler(fromIndex).SetTensorInfo(tensorInfo);
47 // Helper function to create tensor handlers for workloads, assuming they all use the same factory.
48 void CreateTensorHandles(armnn::Graph& graph, armnn::IWorkloadFactory& factory)
50 for (auto&& layer : graph.TopologicalSort())
52 layer->CreateTensorHandles(graph, factory);
56 /////////////////////////////////////////////////////////////////////////////////////////////
57 // The following functions are called by backends/test/CreateWorkload*.cpp
58 // They build very simple graphs, and then create a workload.
59 // Some checks are performed on the workload to ensure parameters have been passed correctly.
60 // They return the created workloads so that backend-specific checks can be performed.
61 /////////////////////////////////////////////////////////////////////////////////////////////
63 template <typename ActivationWorkload, armnn::DataType DataType>
64 std::unique_ptr<ActivationWorkload> CreateActivationWorkloadTest(armnn::IWorkloadFactory& factory,
67 // Creates the layer we're testing.
68 ActivationDescriptor layerDesc;
69 layerDesc.m_Function = ActivationFunction::Abs;
71 layerDesc.m_B = -10.0f;
73 ActivationLayer* const layer = graph.AddLayer<ActivationLayer>(layerDesc, "layer");
75 // Creates extra layers.
76 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
77 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
80 armnn::TensorInfo tensorInfo({1, 1}, DataType);
82 Connect(input, layer, tensorInfo);
83 Connect(layer, output, tensorInfo);
85 CreateTensorHandles(graph, factory);
87 // Makes the workload and checks it.
88 auto workload = MakeAndCheckWorkload<ActivationWorkload>(*layer, graph, factory);
90 ActivationQueueDescriptor queueDescriptor = workload->GetData();
91 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
92 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
93 BOOST_TEST(queueDescriptor.m_Parameters.m_A == 3.5f);
94 BOOST_TEST(queueDescriptor.m_Parameters.m_B == -10.0f);
95 BOOST_TEST((queueDescriptor.m_Parameters.m_Function == ActivationFunction::Abs));
97 // Returns so we can do extra, backend-specific tests.
101 template <typename WorkloadType,
102 typename DescriptorType,
104 armnn::DataType DataType>
105 std::unique_ptr<WorkloadType> CreateArithmeticWorkloadTest(armnn::IWorkloadFactory& factory,
108 // Creates the layer we're testing.
109 Layer* const layer = graph.AddLayer<LayerType>("layer");
111 // Creates extra layers.
112 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
113 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
114 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
117 armnn::TensorInfo tensorInfo({2, 3}, DataType);
118 Connect(input1, layer, tensorInfo, 0, 0);
119 Connect(input2, layer, tensorInfo, 0, 1);
120 Connect(layer, output, tensorInfo);
121 CreateTensorHandles(graph, factory);
123 // Makes the workload and checks it.
124 auto workload = MakeAndCheckWorkload<WorkloadType>(*layer, graph, factory);
126 DescriptorType queueDescriptor = workload->GetData();
127 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
128 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
130 // Returns so we can do extra, backend-specific tests.
134 template <typename BatchNormalizationFloat32Workload, armnn::DataType DataType>
135 std::unique_ptr<BatchNormalizationFloat32Workload> CreateBatchNormalizationWorkloadTest(
136 armnn::IWorkloadFactory& factory, armnn::Graph& graph, DataLayoutIndexed dataLayout = DataLayout::NCHW)
139 TensorShape tensorShape;
140 switch (dataLayout.GetDataLayout())
142 case DataLayout::NHWC:
143 tensorShape = { 2, 4, 4, 3 };
145 case DataLayout::NCHW:
147 tensorShape = { 2, 3, 4, 4 };
150 // Creates the layer we're testing.
151 BatchNormalizationDescriptor layerDesc;
152 layerDesc.m_Eps = 0.05f;
153 layerDesc.m_DataLayout = dataLayout;
155 BatchNormalizationLayer* const layer = graph.AddLayer<BatchNormalizationLayer>(layerDesc, "layer");
157 armnn::TensorInfo weightInfo({3}, DataType);
158 layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
159 layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
160 layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
161 layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
162 layer->m_Mean->Allocate();
163 layer->m_Variance->Allocate();
164 layer->m_Beta->Allocate();
165 layer->m_Gamma->Allocate();
167 // Creates extra layers.
168 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
169 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
172 armnn::TensorInfo tensorInfo(tensorShape, DataType);
173 Connect(input, layer, tensorInfo);
174 Connect(layer, output, tensorInfo);
175 CreateTensorHandles(graph, factory);
177 // Makes the workload and checks it.
178 auto workload = MakeAndCheckWorkload<BatchNormalizationFloat32Workload>(*layer, graph, factory);
179 BatchNormalizationQueueDescriptor queueDescriptor = workload->GetData();
180 BOOST_TEST(queueDescriptor.m_Parameters.m_Eps == 0.05f);
181 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
182 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
183 BOOST_TEST((queueDescriptor.m_Mean->GetTensorInfo() == TensorInfo({3}, DataType)));
184 BOOST_TEST((queueDescriptor.m_Variance->GetTensorInfo() == TensorInfo({3}, DataType)));
185 BOOST_TEST((queueDescriptor.m_Gamma->GetTensorInfo() == TensorInfo({3}, DataType)));
186 BOOST_TEST((queueDescriptor.m_Beta->GetTensorInfo() == TensorInfo({3}, DataType)));
187 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout.GetDataLayout() == dataLayout));
189 // Returns so we can do extra, backend-specific tests.
193 template <typename Convolution2dWorkload, armnn::DataType DataType>
194 std::unique_ptr<Convolution2dWorkload> CreateConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
196 DataLayout dataLayout = DataLayout::NCHW)
198 // Creates the layer we're testing.
199 Convolution2dDescriptor layerDesc;
200 layerDesc.m_PadLeft = 3;
201 layerDesc.m_PadRight = 3;
202 layerDesc.m_PadTop = 1;
203 layerDesc.m_PadBottom = 1;
204 layerDesc.m_StrideX = 2;
205 layerDesc.m_StrideY = 4;
206 layerDesc.m_BiasEnabled = true;
207 layerDesc.m_DataLayout = dataLayout;
209 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
211 TensorShape weightShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 5, 3} : TensorShape{2, 5, 3, 3};
212 TensorShape inputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 8, 16} : TensorShape{2, 8, 16, 3};
213 TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 2, 2, 10} : TensorShape{2, 2, 10, 2};
215 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo(weightShape, DataType));
216 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
218 layer->m_Weight->Allocate();
219 layer->m_Bias->Allocate();
221 // Creates extra layers.
222 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
223 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
226 Connect(input, layer, TensorInfo(inputShape, DataType));
227 Connect(layer, output, TensorInfo(outputShape, DataType));
228 CreateTensorHandles(graph, factory);
230 // Makes the workload and checks it.
231 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
233 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
234 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
235 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
236 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
237 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
238 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
239 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
240 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled);
241 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
243 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
244 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
245 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo(weightShape, DataType)));
246 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() ==
247 TensorInfo({2}, GetBiasDataType(DataType))));
249 // Returns so we can do extra, backend-specific tests.
253 template <typename LstmWorkload>
254 std::unique_ptr<LstmWorkload> CreateLstmWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
256 // This parameter setting is for withCifgWithPeepholeNoProjection
257 LstmDescriptor layerDesc;
258 layerDesc.m_ActivationFunc = 4;
259 layerDesc.m_ClippingThresCell = 0.0f;
260 layerDesc.m_ClippingThresProj = 0.0f;
261 layerDesc.m_CifgEnabled = true;
262 layerDesc.m_PeepholeEnabled = true;
263 layerDesc.m_ProjectionEnabled = false;
265 LstmLayer* const layer = graph.AddLayer<LstmLayer>(layerDesc, "layer");
266 unsigned int batchSize = 2;
267 unsigned int inputSize = 2;
268 unsigned int numUnits = 4;
269 unsigned int outputSize = 4;
271 layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
272 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
273 layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>
274 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
275 layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
276 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
277 layer->m_BasicParameters.m_RecurrentToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
278 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
279 layer->m_BasicParameters.m_RecurrentToCellWeights = std::make_unique<ScopedCpuTensorHandle>
280 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
281 layer->m_BasicParameters.m_RecurrentToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
282 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
283 layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>
284 (TensorInfo({ numUnits }, DataType::Float32));
285 layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>
286 (TensorInfo({ numUnits }, DataType::Float32));
287 layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>
288 (TensorInfo({ numUnits }, DataType::Float32));
290 layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
291 layer->m_BasicParameters.m_InputToCellWeights->Allocate();
292 layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
293 layer->m_BasicParameters.m_RecurrentToForgetWeights->Allocate();
294 layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
295 layer->m_BasicParameters.m_RecurrentToOutputWeights->Allocate();
296 layer->m_BasicParameters.m_ForgetGateBias->Allocate();
297 layer->m_BasicParameters.m_CellBias->Allocate();
298 layer->m_BasicParameters.m_OutputGateBias->Allocate();
301 if (layerDesc.m_PeepholeEnabled)
303 layer->m_PeepholeParameters.m_CellToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
304 (TensorInfo({ numUnits }, DataType::Float32));
305 layer->m_PeepholeParameters.m_CellToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
306 (TensorInfo({ numUnits }, DataType::Float32));
307 layer->m_PeepholeParameters.m_CellToForgetWeights->Allocate();
308 layer->m_PeepholeParameters.m_CellToOutputWeights->Allocate();
311 // create input and output layers
312 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
313 Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
314 Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
315 Layer* const scratchBuffer = graph.AddLayer<OutputLayer>(0, "scratchBuffer");
316 Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
317 Layer* const cellStateOut = graph.AddLayer<OutputLayer>(2, "cellStateOut");
318 Layer* const output = graph.AddLayer<OutputLayer>(3, "output");
321 armnn::TensorInfo lstmTensorInfo1({ batchSize, inputSize }, DataType::Float32);
322 armnn::TensorInfo lstmTensorInfo2({ batchSize, numUnits}, DataType::Float32);
323 armnn::TensorInfo lstmTensorInfo3({ batchSize, outputSize }, DataType::Float32);
324 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits*3 }, DataType::Float32);
325 if (layerDesc.m_CifgEnabled)
327 lstmTensorInfoScratchBuff.SetShape({ batchSize, numUnits*4 });
330 Connect(input, layer, lstmTensorInfo1, 0, 0);
331 Connect(cellStateIn, layer, lstmTensorInfo2, 0, 1);
332 Connect(outputStateIn, layer, lstmTensorInfo3, 0, 2);
333 Connect(layer, scratchBuffer, lstmTensorInfoScratchBuff, 0, 0);
334 Connect(layer, outputStateOut, lstmTensorInfo3, 1, 0);
335 Connect(layer, cellStateOut, lstmTensorInfo2, 2, 0);
336 Connect(layer, output, lstmTensorInfo3, 3, 0);
338 CreateTensorHandles(graph, factory);
340 // make the workload and check it
341 auto workload = MakeAndCheckWorkload<LstmWorkload>(*layer, graph, factory);
342 LstmQueueDescriptor queueDescriptor = workload->GetData();
343 BOOST_TEST(queueDescriptor.m_Parameters.m_ActivationFunc == 4);
344 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresCell == 0.0f);
345 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresProj == 0.0f);
346 BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
347 BOOST_TEST(queueDescriptor.m_Outputs.size() == 4);
349 BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == TensorInfo({ numUnits, inputSize },
350 DataType::Float32)));
351 BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == TensorInfo({ numUnits },
352 DataType::Float32)));
353 BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == TensorInfo({ numUnits }, DataType::Float32)));
357 template <typename Convolution2dWorkload, armnn::DataType DataType>
358 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
361 // Creates the layer we're testing.
362 Convolution2dDescriptor layerDesc;
363 layerDesc.m_PadLeft = 1;
364 layerDesc.m_PadRight = 1;
365 layerDesc.m_PadTop = 1;
366 layerDesc.m_PadBottom = 1;
367 layerDesc.m_StrideX = 1;
368 layerDesc.m_StrideY = 1;
369 layerDesc.m_BiasEnabled = true;
371 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
373 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
374 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
376 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({ 2, 3, 3, 3 }, DataType, inputsQScale));
377 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>
378 (TensorInfo({2}, GetBiasDataType(DataType), inputsQScale));
379 layer->m_Weight->Allocate();
380 layer->m_Bias->Allocate();
382 // Creates extra layers.
383 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
384 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
387 Connect(input, layer, TensorInfo({2, 3, 6, 6}, DataType, inputsQScale));
388 Connect(layer, output, TensorInfo({2, 2, 6, 6}, DataType, outputQScale));
389 CreateTensorHandles(graph, factory);
391 // Makes the workload and checks it.
392 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
394 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
395 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
396 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
397 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
398 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 1);
399 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
400 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
401 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
403 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
404 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
405 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 3, 3},
406 DataType, inputsQScale)));
407 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo()
408 == TensorInfo({2}, GetBiasDataType(DataType), inputsQScale)));
410 // Returns so we can do extra, backend-specific tests.
414 template <typename DepthwiseConvolution2dFloat32Workload, armnn::DataType DataType>
415 std::unique_ptr<DepthwiseConvolution2dFloat32Workload> CreateDepthwiseConvolution2dWorkloadTest(
416 armnn::IWorkloadFactory& factory, armnn::Graph& graph, DataLayout dataLayout = DataLayout::NCHW)
418 // Creates the layer we're testing.
419 DepthwiseConvolution2dDescriptor layerDesc;
420 layerDesc.m_PadLeft = 1;
421 layerDesc.m_PadRight = 2;
422 layerDesc.m_PadTop = 1;
423 layerDesc.m_PadBottom = 2;
424 layerDesc.m_StrideX = 1;
425 layerDesc.m_StrideY = 1;
426 layerDesc.m_BiasEnabled = false;
427 layerDesc.m_DataLayout = dataLayout;
429 DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
431 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({1, 4, 4, 2}, DataType));
432 layer->m_Weight->Allocate();
434 // Creates extra layers.
435 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
436 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
438 TensorShape inputShape = (dataLayout == DataLayout::NCHW) ?
439 TensorShape{ 2, 2, 5, 5 } : TensorShape{ 2, 5, 5, 2 };
440 TensorShape outputShape = (dataLayout == DataLayout::NCHW) ?
441 TensorShape{ 2, 2, 5, 5 } : TensorShape{ 2, 5, 5, 2 };
444 Connect(input, layer, TensorInfo(inputShape, DataType));
445 Connect(layer, output, TensorInfo(outputShape, DataType));
446 CreateTensorHandles(graph, factory);
448 // Makes the workload and checks it.
449 auto workload = MakeAndCheckWorkload<DepthwiseConvolution2dFloat32Workload>(*layer, graph, factory);
451 DepthwiseConvolution2dQueueDescriptor queueDescriptor = workload->GetData();
452 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
453 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
454 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
455 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
456 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
457 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 2);
458 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == false);
459 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
461 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
462 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
463 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({1, 4, 4, 2}, DataType)));
465 // Returns so we can do extra, backend-specific tests.
469 template <typename FullyConnectedWorkload, armnn::DataType DataType>
470 std::unique_ptr<FullyConnectedWorkload> CreateFullyConnectedWorkloadTest(armnn::IWorkloadFactory& factory,
473 // Creates the layer we're testing.
474 FullyConnectedDescriptor layerDesc;
475 layerDesc.m_BiasEnabled = true;
476 layerDesc.m_TransposeWeightMatrix = true;
478 FullyConnectedLayer* const layer = graph.AddLayer<FullyConnectedLayer>(layerDesc, "layer");
480 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
481 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
483 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7, 20}, DataType, inputsQScale, 0));
484 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7}, GetBiasDataType(DataType), inputsQScale));
485 layer->m_Weight->Allocate();
486 layer->m_Bias->Allocate();
488 // Creates extra layers.
489 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
490 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
493 Connect(input, layer, TensorInfo({3, 1, 4, 5}, DataType, inputsQScale));
494 Connect(layer, output, TensorInfo({3, 7}, DataType, outputQScale));
495 CreateTensorHandles(graph, factory);
497 // Makes the workload and checks it.
498 auto workload = MakeAndCheckWorkload<FullyConnectedWorkload>(*layer, graph, factory);
500 FullyConnectedQueueDescriptor queueDescriptor = workload->GetData();
501 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
502 BOOST_TEST(queueDescriptor.m_Parameters.m_TransposeWeightMatrix == true);
504 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
505 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
506 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({7, 20}, DataType, inputsQScale)));
507 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({7}, GetBiasDataType(DataType), inputsQScale)));
509 // Returns so we can do extra, backend-specific tests.
513 template <typename NormalizationWorkload, armnn::DataType DataType>
514 std::unique_ptr<NormalizationWorkload> CreateNormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
516 DataLayout dataLayout = DataLayout::NCHW)
518 // Creates the layer we're testing.
519 NormalizationDescriptor layerDesc;
520 layerDesc.m_NormChannelType = NormalizationAlgorithmChannel::Across;
521 layerDesc.m_NormMethodType = NormalizationAlgorithmMethod::LocalBrightness;
522 layerDesc.m_NormSize = 3;
523 layerDesc.m_Alpha = 0.5f;
524 layerDesc.m_Beta = -1.0f;
525 layerDesc.m_K = 0.2f;
526 layerDesc.m_DataLayout = dataLayout;
528 NormalizationLayer* layer = graph.AddLayer<NormalizationLayer>(layerDesc, "layer");
530 // Creates extra layers.
531 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
532 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
534 TensorShape inputShape = (dataLayout == DataLayout::NCHW) ?
535 TensorShape{ 3, 5, 5, 1 } : TensorShape{ 3, 1, 5, 5 };
536 TensorShape outputShape = (dataLayout == DataLayout::NCHW) ?
537 TensorShape{ 3, 5, 5, 1 } : TensorShape{ 3, 1, 5, 5 };
540 armnn::TensorInfo inputTensorInfo(inputShape, DataType);
541 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
542 Connect(input, layer, inputTensorInfo);
543 Connect(layer, output, outputTensorInfo);
544 CreateTensorHandles(graph, factory);
546 // Makes the workload and checks it.
547 auto workload = MakeAndCheckWorkload<NormalizationWorkload>(*layer, graph, factory);
549 NormalizationQueueDescriptor queueDescriptor = workload->GetData();
550 BOOST_TEST((queueDescriptor.m_Parameters.m_NormChannelType == NormalizationAlgorithmChannel::Across));
551 BOOST_TEST((queueDescriptor.m_Parameters.m_NormMethodType == NormalizationAlgorithmMethod::LocalBrightness));
552 BOOST_TEST(queueDescriptor.m_Parameters.m_NormSize == 3);
553 BOOST_TEST(queueDescriptor.m_Parameters.m_Alpha == 0.5f);
554 BOOST_TEST(queueDescriptor.m_Parameters.m_Beta == -1.0f);
555 BOOST_TEST(queueDescriptor.m_Parameters.m_K == 0.2f);
556 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
558 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
559 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
561 // Returns so we can do extra, backend-specific tests.
565 template <typename Pooling2dWorkload, armnn::DataType DataType>
566 std::unique_ptr<Pooling2dWorkload> CreatePooling2dWorkloadTest(armnn::IWorkloadFactory& factory,
568 DataLayout dataLayout = DataLayout::NCHW)
570 // Creates the layer we're testing.
571 Pooling2dDescriptor layerDesc;
572 layerDesc.m_PoolType = PoolingAlgorithm::Average;
573 layerDesc.m_PoolWidth = 3;
574 layerDesc.m_PoolHeight = 3;
575 layerDesc.m_PadLeft = 2;
576 layerDesc.m_PadRight = 2;
577 layerDesc.m_PadTop = 1;
578 layerDesc.m_PadBottom = 1;
579 layerDesc.m_StrideX = 2;
580 layerDesc.m_StrideY = 3;
581 layerDesc.m_OutputShapeRounding = OutputShapeRounding::Floor;
582 layerDesc.m_DataLayout = dataLayout;
584 Pooling2dLayer* const layer = graph.AddLayer<Pooling2dLayer>(layerDesc, "layer");
586 // Create extra layers
587 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
588 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
590 TensorShape inputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{3, 2, 5, 5} : TensorShape{3, 5, 5, 2};
591 TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{3, 2, 2, 4} : TensorShape{3, 2, 4, 2};
594 Connect(input, layer, TensorInfo(inputShape, DataType));
595 Connect(layer, output, TensorInfo(outputShape, DataType));
596 CreateTensorHandles(graph, factory);
598 // Make the workload and checks it
599 auto workload = MakeAndCheckWorkload<Pooling2dWorkload>(*layer, graph, factory);
601 Pooling2dQueueDescriptor queueDescriptor = workload->GetData();
602 BOOST_TEST((queueDescriptor.m_Parameters.m_PoolType == PoolingAlgorithm::Average));
603 BOOST_TEST((queueDescriptor.m_Parameters.m_OutputShapeRounding == OutputShapeRounding::Floor));
604 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolWidth == 3);
605 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolHeight == 3);
606 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
607 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 3);
608 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 2);
609 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
610 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
611 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
612 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
614 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
615 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
617 // Return so we can do extra, backend-specific tests
621 template <typename SoftmaxWorkload, armnn::DataType DataType>
622 std::unique_ptr<SoftmaxWorkload> CreateSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory,
625 // Create the layer we're testing.
626 SoftmaxDescriptor softmaxDescriptor;
627 Layer* const layer = graph.AddLayer<SoftmaxLayer>(softmaxDescriptor, "layer");
629 // Create extra layers.
630 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
631 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
634 armnn::TensorInfo tensorInfo({4, 1}, DataType);
635 Connect(input, layer, tensorInfo);
636 Connect(layer, output, tensorInfo);
637 CreateTensorHandles(graph, factory);
639 // Make the workload and checks it.
640 auto workload = MakeAndCheckWorkload<SoftmaxWorkload>(*layer, graph, factory);
642 SoftmaxQueueDescriptor queueDescriptor = workload->GetData();
643 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
644 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
646 // Return so we can do extra, backend-specific tests.
650 template<typename SplitterWorkload, armnn::DataType DataType>
651 std::unique_ptr<SplitterWorkload>
652 CreateSplitterWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
654 // Create the layer we're testing.
655 // NOTE: need three dimensions channels, height/y, width/x because the Compute
656 // library restricts subtensors to have the same x and y dimensions as
657 // their parent tensors, and therefore the origin on the x and y dimension
658 // has to be zero for any view. So we need a third dimension to split...
659 // NOTE: arguments are: number of views, number of dimensions.
660 ViewsDescriptor layerDesc(3, 3);
661 // NOTE: arguments are: view, dimension, value.
662 layerDesc.SetViewOriginCoord(0, 0, 0);
663 layerDesc.SetViewOriginCoord(1, 0, 1);
664 layerDesc.SetViewOriginCoord(2, 0, 3);
666 Layer* const layer = graph.AddLayer<SplitterLayer>(layerDesc, "layer");
668 // Adds extra layers.
669 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
670 Layer* const output0 = graph.AddLayer<OutputLayer>(0, "output0");
671 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
672 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
675 armnn::TensorInfo tensorInfo({5, 7, 7}, DataType);
676 Connect(input, layer, tensorInfo);
678 armnn::TensorInfo output0Info({1, 7, 7}, DataType);
679 armnn::TensorInfo output1Info({2, 7, 7}, DataType);
680 armnn::TensorInfo output2Info({2, 7, 7}, DataType);
682 Connect(layer, output0, output0Info, 0, 0);
683 Connect(layer, output1, output1Info, 1, 0);
684 Connect(layer, output2, output2Info, 2, 0);
686 CreateTensorHandles(graph, factory);
688 // Makes the workload and checks it.
689 auto workload = MakeAndCheckWorkload<SplitterWorkload>(*layer, graph, factory);
691 SplitterQueueDescriptor queueDescriptor = workload->GetData();
692 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
693 BOOST_TEST(queueDescriptor.m_Outputs.size() == 3);
694 BOOST_TEST(queueDescriptor.m_ViewOrigins.size() == 3);
696 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[0] == 0);
697 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[0] == 1);
698 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[0] == 3);
699 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[1] == 0);
700 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[1] == 0);
701 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[1] == 0);
702 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[2] == 0);
703 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[2] == 0);
704 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[2] == 0);
706 // Returns so we can do extra, backend-specific tests.
710 /// This function constructs a graph with both a splitter and a merger, and returns a pair of the workloads.
711 template<typename SplitterWorkload, typename MergerWorkload, armnn::DataType DataType>
712 std::pair<std::unique_ptr<SplitterWorkload>, std::unique_ptr<MergerWorkload>>
713 CreateSplitterMergerWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
715 armnn::TensorInfo inputTensorInfo({ 1, 2, 100, 10 }, DataType);
717 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 10 }, DataType);
718 armnn::TensorInfo splitTensorInfo2({ 1, 1, 100, 10 }, DataType);
720 //Constructs the graph.
721 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
723 armnn::ViewsDescriptor splitterViews(2);
724 splitterViews.SetViewOriginCoord(0, 0, 0);
725 splitterViews.SetViewOriginCoord(0, 1, 0);
726 splitterViews.SetViewOriginCoord(0, 2, 0);
727 splitterViews.SetViewOriginCoord(0, 3, 0);
729 splitterViews.SetViewOriginCoord(1, 0, 0);
730 splitterViews.SetViewOriginCoord(1, 1, 1);
731 splitterViews.SetViewOriginCoord(1, 2, 0);
732 splitterViews.SetViewOriginCoord(1, 3, 0);
734 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
735 BOOST_TEST_CHECKPOINT("created splitter layer");
737 armnn::OriginsDescriptor mergerViews(2);
738 mergerViews.SetViewOriginCoord(0, 0, 0);
739 mergerViews.SetViewOriginCoord(0, 1, 1);
740 mergerViews.SetViewOriginCoord(0, 2, 0);
741 mergerViews.SetViewOriginCoord(0, 3, 0);
743 mergerViews.SetViewOriginCoord(1, 0, 0);
744 mergerViews.SetViewOriginCoord(1, 1, 0);
745 mergerViews.SetViewOriginCoord(1, 2, 0);
746 mergerViews.SetViewOriginCoord(1, 3, 0);
748 Layer* const merger = graph.AddLayer<MergerLayer>(mergerViews, "merger");
749 BOOST_TEST_CHECKPOINT("created merger layer");
751 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
754 Connect(input, splitter, inputTensorInfo, 0, 0);
755 BOOST_TEST_CHECKPOINT("connect input to splitter");
756 Connect(splitter, merger, splitTensorInfo1, 0, 1); // The splitter & merger are connected up.
757 BOOST_TEST_CHECKPOINT("connect splitter[0] to merger[1]");
758 Connect(splitter, merger, splitTensorInfo2, 1, 0); // So that the outputs are flipped round.
759 BOOST_TEST_CHECKPOINT("connect splitter[1] to merger[0]");
760 Connect(merger, output, inputTensorInfo, 0, 0);
761 BOOST_TEST_CHECKPOINT("connect merger to output");
763 CreateTensorHandles(graph, factory);
764 BOOST_TEST_CHECKPOINT("created tensor handles");
766 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
767 BOOST_TEST_CHECKPOINT("created splitter workload");
768 auto workloadMerger = MakeAndCheckWorkload<MergerWorkload>(*merger, graph, factory);
769 BOOST_TEST_CHECKPOINT("created merger workload");
771 return {std::move(workloadSplitter), std::move(workloadMerger)};
775 /// This function constructs a graph with a splitter with two outputs. Each of the outputs is then
776 /// connected to two different activation layers
777 template<typename SplitterWorkload, typename ActivationWorkload, armnn::DataType DataType>
778 void CreateSplitterMultipleInputsOneOutputWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph,
779 std::unique_ptr<SplitterWorkload>& wlSplitter,
780 std::unique_ptr<ActivationWorkload>& wlActiv0_0,
781 std::unique_ptr<ActivationWorkload>& wlActiv0_1,
782 std::unique_ptr<ActivationWorkload>& wlActiv1_0,
783 std::unique_ptr<ActivationWorkload>& wlActiv1_1)
785 armnn::TensorInfo inputTensorInfo ({ 1, 3, 100, 50 }, DataType);
786 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 50 }, DataType);
787 armnn::TensorInfo splitTensorInfo2({ 1, 2, 100, 50 }, DataType);
789 //Constructs the graph.
790 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
792 armnn::ViewsDescriptor splitterViews(2);
794 splitterViews.SetViewOriginCoord(0, 0, 0);
795 splitterViews.SetViewOriginCoord(0, 1, 0);
796 splitterViews.SetViewOriginCoord(0, 2, 0);
797 splitterViews.SetViewOriginCoord(0, 3, 0);
799 splitterViews.SetViewOriginCoord(1, 0, 0);
800 splitterViews.SetViewOriginCoord(1, 1, 1);
801 splitterViews.SetViewOriginCoord(1, 2, 0);
802 splitterViews.SetViewOriginCoord(1, 3, 0);
804 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
806 armnn::ActivationDescriptor activationDesc;
808 Layer* const activ0_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_0");
809 Layer* const activ0_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_1");
810 Layer* const activ1_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_0");
811 Layer* const activ1_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_1");
813 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
814 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
815 Layer* const output3 = graph.AddLayer<OutputLayer>(3, "output3");
816 Layer* const output4 = graph.AddLayer<OutputLayer>(4, "output4");
819 Connect(input, splitter, inputTensorInfo, 0, 0);
820 Connect(splitter, activ0_0, splitTensorInfo1, 0, 0);
821 Connect(splitter, activ0_1, splitTensorInfo1, 0, 0);
823 Connect(splitter, activ1_0, splitTensorInfo2, 1, 0);
824 Connect(splitter, activ1_1, splitTensorInfo2, 1, 0);
826 Connect(activ0_0, output1, splitTensorInfo1, 0, 0);
827 Connect(activ0_1, output2, splitTensorInfo1, 0, 0);
828 Connect(activ1_0, output3, splitTensorInfo2, 0, 0);
829 Connect(activ1_1, output4, splitTensorInfo2, 0, 0);
831 CreateTensorHandles(graph, factory);
833 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
834 auto workloadActiv0_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_0, graph, factory);
835 auto workloadActiv0_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_1, graph, factory);
836 auto workloadActiv1_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_0, graph, factory);
837 auto workloadActiv1_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_1, graph, factory);
839 wlSplitter = std::move(workloadSplitter);
840 wlActiv0_0 = std::move(workloadActiv0_0);
841 wlActiv0_1 = std::move(workloadActiv0_1);
842 wlActiv1_0 = std::move(workloadActiv1_0);
843 wlActiv1_1 = std::move(workloadActiv1_1);
846 template <typename ResizeBilinearWorkload, armnn::DataType DataType>
847 std::unique_ptr<ResizeBilinearWorkload> CreateResizeBilinearWorkloadTest(armnn::IWorkloadFactory& factory,
849 DataLayoutIndexed dataLayout =
852 TensorShape inputShape;
853 TensorShape outputShape;
855 switch (dataLayout.GetDataLayout()) {
856 case DataLayout::NHWC:
857 inputShape = { 2, 4, 4, 3 };
858 outputShape = { 2, 2, 2, 3 };
860 case DataLayout::NCHW:
862 inputShape = { 2, 3, 4, 4 };
863 outputShape = { 2, 3, 2, 2 };
866 // Creates the layer we're testing.
867 ResizeBilinearDescriptor resizeDesc;
868 resizeDesc.m_TargetWidth = outputShape[dataLayout.GetWidthIndex()];
869 resizeDesc.m_TargetHeight = outputShape[dataLayout.GetHeightIndex()];
870 resizeDesc.m_DataLayout = dataLayout;
871 Layer* const layer = graph.AddLayer<ResizeBilinearLayer>(resizeDesc, "layer");
873 // Creates extra layers.
874 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
875 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
878 armnn::TensorInfo inputTensorInfo(inputShape, DataType);
879 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
880 Connect(input, layer, inputTensorInfo);
881 Connect(layer, output, outputTensorInfo);
882 CreateTensorHandles(graph, factory);
884 // Makes the workload and checks it.
885 auto workload = MakeAndCheckWorkload<ResizeBilinearWorkload>(*layer, graph, factory);
887 ResizeBilinearQueueDescriptor queueDescriptor = workload->GetData();
888 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
889 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
890 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout.GetDataLayout() == dataLayout));
892 // Returns so we can do extra, backend-specific tests.
896 template <typename L2NormalizationWorkload, armnn::DataType DataType>
897 std::unique_ptr<L2NormalizationWorkload> CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
898 armnn::Graph& graph, DataLayout dataLayout = DataLayout::NCHW)
900 // Creates the layer we're testing.
901 L2NormalizationDescriptor layerDesc;
902 layerDesc.m_DataLayout = dataLayout;
904 Layer* const layer = graph.AddLayer<L2NormalizationLayer>(layerDesc, "l2norm");
906 // Creates extra layers.
907 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
908 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
910 TensorShape inputShape = (dataLayout == DataLayout::NCHW) ?
911 TensorShape{ 5, 20, 50, 67 } : TensorShape{ 5, 50, 67, 20 };
912 TensorShape outputShape = (dataLayout == DataLayout::NCHW) ?
913 TensorShape{ 5, 20, 50, 67 } : TensorShape{ 5, 50, 67, 20 };
916 armnn::TensorInfo inputTensorInfo(inputShape, DataType);
917 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
918 Connect(input, layer, inputTensorInfo);
919 Connect(layer, output, outputTensorInfo);
920 CreateTensorHandles(graph, factory);
922 // Makes the workload and checks it.
923 auto workload = MakeAndCheckWorkload<L2NormalizationWorkload>(*layer, graph, factory);
925 L2NormalizationQueueDescriptor queueDescriptor = workload->GetData();
926 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
927 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
928 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
930 // Returns so we can do extra, backend-specific tests.
934 template <typename ReshapeWorkload, armnn::DataType DataType>
935 std::unique_ptr<ReshapeWorkload> CreateReshapeWorkloadTest(armnn::IWorkloadFactory& factory,
938 // Creates the layer we're testing.
939 TensorShape outputShape({ 1, 4 });
940 ReshapeDescriptor reshapeDesc;
941 reshapeDesc.m_TargetShape = outputShape;
942 Layer* const layer = graph.AddLayer<ReshapeLayer>(reshapeDesc, "layer");
944 // Creates extra layers.
945 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
946 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
949 armnn::TensorInfo inputTensorInfo({ 4, 1 }, DataType);
950 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
951 Connect(input, layer, inputTensorInfo);
952 Connect(layer, output, outputTensorInfo);
953 CreateTensorHandles(graph, factory);
955 // Makes the workload and checks it.
956 auto workload = MakeAndCheckWorkload<ReshapeWorkload>(*layer, graph, factory);
958 ReshapeQueueDescriptor queueDescriptor = workload->GetData();
959 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
960 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
962 // Returns so we can do extra, backend-specific tests.
966 template <typename ConvertFp16ToFp32Float32Workload>
967 std::unique_ptr<ConvertFp16ToFp32Float32Workload> CreateConvertFp16ToFp32WorkloadTest(
968 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
970 // Creates the layer we're testing.
971 ConvertFp16ToFp32Layer* const layer = graph.AddLayer<ConvertFp16ToFp32Layer>("Fp16ToFp32Converter");
973 // Creates extra layers.
974 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
975 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
978 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
979 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
980 Connect(input, layer, inputTensorInfo);
981 Connect(layer, output, outputTensorInfo);
982 CreateTensorHandles(graph, factory);
984 // Makes the workload and checks it.
985 auto workload = MakeAndCheckWorkload<ConvertFp16ToFp32Float32Workload>(*layer, graph, factory);
987 ConvertFp16ToFp32QueueDescriptor queueDescriptor = workload->GetData();
988 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
989 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
991 // Returns so we can do extra, backend-specific tests.
995 template <typename ConvertFp32ToFp16Float16Workload>
996 std::unique_ptr<ConvertFp32ToFp16Float16Workload> CreateConvertFp32ToFp16WorkloadTest(
997 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
999 // Creates the layer we're testing.
1000 ConvertFp32ToFp16Layer* const layer = graph.AddLayer<ConvertFp32ToFp16Layer>("Fp32ToFp16Converter");
1002 // Creates extra layers.
1003 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1004 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1007 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
1008 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
1009 Connect(input, layer, inputTensorInfo);
1010 Connect(layer, output, outputTensorInfo);
1011 CreateTensorHandles(graph, factory);
1013 // Makes the workload and checks it.
1014 auto workload = MakeAndCheckWorkload<ConvertFp32ToFp16Float16Workload>(*layer, graph, factory);
1016 ConvertFp32ToFp16QueueDescriptor queueDescriptor = workload->GetData();
1017 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1018 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1020 // Returns so we can do extra, backend-specific tests.
1024 template <typename MeanWorkload, armnn::DataType DataType>
1025 std::unique_ptr<MeanWorkload> CreateMeanWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
1027 // Reduce along the first and second dimensions, and do not keep the reduced dimensions.
1028 MeanDescriptor descriptor({ 1, 2 }, false);
1030 // Creates the layer we're testing.
1031 Layer* const layer = graph.AddLayer<MeanLayer>(descriptor, "mean");
1033 // Creates extra layers.
1034 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1035 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1038 armnn::TensorInfo inputTensorInfo({ 1, 3, 7, 4 }, DataType);
1039 armnn::TensorInfo outputTensorInfo({ 1, 4 }, DataType);
1040 Connect(input, layer, inputTensorInfo);
1041 Connect(layer, output, outputTensorInfo);
1042 CreateTensorHandles(graph, factory);
1044 // Makes the workload and checks it.
1045 auto workload = MakeAndCheckWorkload<MeanWorkload>(*layer, graph, factory);
1047 MeanQueueDescriptor queueDescriptor = workload->GetData();
1048 BOOST_TEST(queueDescriptor.m_Parameters.m_Axis == descriptor.m_Axis);
1049 BOOST_TEST(queueDescriptor.m_Parameters.m_KeepDims == descriptor.m_KeepDims);
1050 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1051 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1053 // Returns so we can do extra, backend-specific tests.