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"
16 #include "backends/CpuTensorHandle.hpp"
18 using namespace armnn;
25 // Calls CreateWorkload for a layer, and checks the returned pointer is of the correct type.
26 template<typename Workload>
27 std::unique_ptr<Workload> MakeAndCheckWorkload(Layer& layer, Graph& graph, const IWorkloadFactory& factory)
29 std::unique_ptr<IWorkload> workload = layer.CreateWorkload(graph, factory);
30 BOOST_TEST(workload.get() == boost::polymorphic_downcast<Workload*>(workload.get()),
31 "Cannot convert to derived class");
32 std::string reasonIfUnsupported;
33 layer.SetComputeDevice(factory.GetCompute());
34 BOOST_TEST(factory.IsLayerSupported(layer, layer.GetDataType(), reasonIfUnsupported));
35 return std::unique_ptr<Workload>(static_cast<Workload*>(workload.release()));
38 // Connects two layers.
39 void Connect(Layer* from, Layer* to, const TensorInfo& tensorInfo, unsigned int fromIndex = 0, unsigned int toIndex = 0)
41 from->GetOutputSlot(fromIndex).Connect(to->GetInputSlot(toIndex));
42 from->GetOutputHandler(fromIndex).SetTensorInfo(tensorInfo);
45 // Helper function to create tensor handlers for workloads, assuming they all use the same factory.
46 void CreateTensorHandles(armnn::Graph& graph, armnn::IWorkloadFactory& factory)
48 for (auto&& layer : graph.TopologicalSort())
50 layer->CreateTensorHandles(graph, factory);
54 /////////////////////////////////////////////////////////////////////////////////////////////
55 // The following functions are called by backends/test/CreateWorkload*.cpp
56 // They build very simple graphs, and then create a workload.
57 // Some checks are performed on the workload to ensure parameters have been passed correctly.
58 // They return the created workloads so that backend-specific checks can be performed.
59 /////////////////////////////////////////////////////////////////////////////////////////////
61 template <typename ActivationWorkload, armnn::DataType DataType>
62 std::unique_ptr<ActivationWorkload> CreateActivationWorkloadTest(armnn::IWorkloadFactory& factory,
65 // Creates the layer we're testing.
66 ActivationDescriptor layerDesc;
67 layerDesc.m_Function = ActivationFunction::Abs;
69 layerDesc.m_B = -10.0f;
71 ActivationLayer* const layer = graph.AddLayer<ActivationLayer>(layerDesc, "layer");
73 // Creates extra layers.
74 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
75 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
78 armnn::TensorInfo tensorInfo({1, 1}, DataType);
80 Connect(input, layer, tensorInfo);
81 Connect(layer, output, tensorInfo);
83 CreateTensorHandles(graph, factory);
85 // Makes the workload and checks it.
86 auto workload = MakeAndCheckWorkload<ActivationWorkload>(*layer, graph, factory);
88 ActivationQueueDescriptor queueDescriptor = workload->GetData();
89 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
90 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
91 BOOST_TEST(queueDescriptor.m_Parameters.m_A == 3.5f);
92 BOOST_TEST(queueDescriptor.m_Parameters.m_B == -10.0f);
93 BOOST_TEST((queueDescriptor.m_Parameters.m_Function == ActivationFunction::Abs));
95 // Returns so we can do extra, backend-specific tests.
99 template <typename AdditionWorkload, armnn::DataType DataType>
100 std::unique_ptr<AdditionWorkload> CreateAdditionWorkloadTest(armnn::IWorkloadFactory& factory,
103 // Creates the layer we're testing.
104 Layer* const layer = graph.AddLayer<AdditionLayer>("layer");
106 // Creates extra layers.
107 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
108 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
109 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
112 armnn::TensorInfo tensorInfo({2, 3}, DataType);
113 Connect(input1, layer, tensorInfo, 0, 0);
114 Connect(input2, layer, tensorInfo, 0, 1);
115 Connect(layer, output, tensorInfo);
116 CreateTensorHandles(graph, factory);
118 // Makes the workload and checks it.
119 auto workload = MakeAndCheckWorkload<AdditionWorkload>(*layer, graph, factory);
121 AdditionQueueDescriptor queueDescriptor = workload->GetData();
122 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
123 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
125 // Returns so we can do extra, backend-specific tests.
129 template <typename WorkloadType,
130 typename DescriptorType,
132 armnn::DataType DataType>
133 std::unique_ptr<WorkloadType> CreateArithmeticWorkloadTest(armnn::IWorkloadFactory& factory,
136 // Creates the layer we're testing.
137 Layer* const layer = graph.AddLayer<LayerType>("layer");
139 // Creates extra layers.
140 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
141 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
142 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
145 armnn::TensorInfo tensorInfo({2, 3}, DataType);
146 Connect(input1, layer, tensorInfo, 0, 0);
147 Connect(input2, layer, tensorInfo, 0, 1);
148 Connect(layer, output, tensorInfo);
149 CreateTensorHandles(graph, factory);
151 // Makes the workload and checks it.
152 auto workload = MakeAndCheckWorkload<WorkloadType>(*layer, graph, factory);
154 DescriptorType queueDescriptor = workload->GetData();
155 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
156 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
158 // Returns so we can do extra, backend-specific tests.
162 template <typename BatchNormalizationFloat32Workload, armnn::DataType DataType>
163 std::unique_ptr<BatchNormalizationFloat32Workload> CreateBatchNormalizationWorkloadTest(
164 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
166 // Creates the layer we're testing.
167 BatchNormalizationDescriptor layerDesc;
168 layerDesc.m_Eps = 0.05f;
170 BatchNormalizationLayer* const layer = graph.AddLayer<BatchNormalizationLayer>(layerDesc, "layer");
172 armnn::TensorInfo weightInfo({3}, DataType);
173 layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
174 layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
175 layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
176 layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
177 layer->m_Mean->Allocate();
178 layer->m_Variance->Allocate();
179 layer->m_Beta->Allocate();
180 layer->m_Gamma->Allocate();
182 // Creates extra layers.
183 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
184 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
187 armnn::TensorInfo tensorInfo({2, 3, 1, 1}, DataType);
188 Connect(input, layer, tensorInfo);
189 Connect(layer, output, tensorInfo);
190 CreateTensorHandles(graph, factory);
192 // Makes the workload and checks it.
193 auto workload = MakeAndCheckWorkload<BatchNormalizationFloat32Workload>(*layer, graph, factory);
195 BatchNormalizationQueueDescriptor queueDescriptor = workload->GetData();
196 BOOST_TEST(queueDescriptor.m_Parameters.m_Eps == 0.05f);
197 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
198 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
199 BOOST_TEST((queueDescriptor.m_Mean->GetTensorInfo() == TensorInfo({3}, DataType)));
200 BOOST_TEST((queueDescriptor.m_Variance->GetTensorInfo() == TensorInfo({3}, DataType)));
201 BOOST_TEST((queueDescriptor.m_Gamma->GetTensorInfo() == TensorInfo({3}, DataType)));
202 BOOST_TEST((queueDescriptor.m_Beta->GetTensorInfo() == TensorInfo({3}, DataType)));
204 // Returns so we can do extra, backend-specific tests.
208 template <typename Convolution2dWorkload, armnn::DataType DataType>
209 std::unique_ptr<Convolution2dWorkload> CreateConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
212 // Creates the layer we're testing.
213 Convolution2dDescriptor layerDesc;
214 layerDesc.m_PadLeft = 3;
215 layerDesc.m_PadRight = 3;
216 layerDesc.m_PadTop = 1;
217 layerDesc.m_PadBottom = 1;
218 layerDesc.m_StrideX = 2;
219 layerDesc.m_StrideY = 4;
220 layerDesc.m_BiasEnabled = true;
222 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
224 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2, 3, 5, 3}, DataType));
225 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
227 layer->m_Weight->Allocate();
228 layer->m_Bias->Allocate();
230 // Creates extra layers.
231 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
232 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
235 Connect(input, layer, TensorInfo({2, 3, 8, 16}, DataType));
236 Connect(layer, output, TensorInfo({2, 2, 2, 10}, DataType));
237 CreateTensorHandles(graph, factory);
239 // Makes the workload and checks it.
240 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
242 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
243 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
244 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
245 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
246 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
247 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
248 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
249 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
251 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
252 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
253 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 5, 3}, DataType)));
254 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() ==
255 TensorInfo({2}, GetBiasDataType(DataType))));
257 // Returns so we can do extra, backend-specific tests.
261 template <typename LstmWorkload>
262 std::unique_ptr<LstmWorkload> CreateLstmWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
264 // This parameter setting is for withCifgWithPeepholeNoProjection
265 LstmDescriptor layerDesc;
266 layerDesc.m_ActivationFunc = 4;
267 layerDesc.m_ClippingThresCell = 0.0f;
268 layerDesc.m_ClippingThresProj = 0.0f;
269 layerDesc.m_CifgEnabled = true;
270 layerDesc.m_PeepholeEnabled = true;
271 layerDesc.m_ProjectionEnabled = false;
273 LstmLayer* const layer = graph.AddLayer<LstmLayer>(layerDesc, "layer");
274 unsigned int batchSize = 2;
275 unsigned int inputSize = 2;
276 unsigned int numUnits = 4;
277 unsigned int outputSize = 4;
279 layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
280 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
281 layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>
282 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
283 layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
284 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
285 layer->m_BasicParameters.m_RecurrentToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
286 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
287 layer->m_BasicParameters.m_RecurrentToCellWeights = std::make_unique<ScopedCpuTensorHandle>
288 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
289 layer->m_BasicParameters.m_RecurrentToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
290 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
291 layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>
292 (TensorInfo({ numUnits }, DataType::Float32));
293 layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>
294 (TensorInfo({ numUnits }, DataType::Float32));
295 layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>
296 (TensorInfo({ numUnits }, DataType::Float32));
298 layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
299 layer->m_BasicParameters.m_InputToCellWeights->Allocate();
300 layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
301 layer->m_BasicParameters.m_RecurrentToForgetWeights->Allocate();
302 layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
303 layer->m_BasicParameters.m_RecurrentToOutputWeights->Allocate();
304 layer->m_BasicParameters.m_ForgetGateBias->Allocate();
305 layer->m_BasicParameters.m_CellBias->Allocate();
306 layer->m_BasicParameters.m_OutputGateBias->Allocate();
309 if (layerDesc.m_PeepholeEnabled)
311 layer->m_PeepholeParameters.m_CellToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
312 (TensorInfo({ numUnits }, DataType::Float32));
313 layer->m_PeepholeParameters.m_CellToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
314 (TensorInfo({ numUnits }, DataType::Float32));
315 layer->m_PeepholeParameters.m_CellToForgetWeights->Allocate();
316 layer->m_PeepholeParameters.m_CellToOutputWeights->Allocate();
319 // create input and output layers
320 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
321 Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
322 Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
323 Layer* const scratchBuffer = graph.AddLayer<OutputLayer>(0, "scratchBuffer");
324 Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
325 Layer* const cellStateOut = graph.AddLayer<OutputLayer>(2, "cellStateOut");
326 Layer* const output = graph.AddLayer<OutputLayer>(3, "output");
329 armnn::TensorInfo lstmTensorInfo1({ batchSize, inputSize }, DataType::Float32);
330 armnn::TensorInfo lstmTensorInfo2({ batchSize, numUnits}, DataType::Float32);
331 armnn::TensorInfo lstmTensorInfo3({ batchSize, outputSize }, DataType::Float32);
332 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits*3 }, DataType::Float32);
333 if (layerDesc.m_CifgEnabled)
335 lstmTensorInfoScratchBuff.SetShape({ batchSize, numUnits*4 });
338 Connect(input, layer, lstmTensorInfo1, 0, 0);
339 Connect(cellStateIn, layer, lstmTensorInfo2, 0, 1);
340 Connect(outputStateIn, layer, lstmTensorInfo3, 0, 2);
341 Connect(layer, scratchBuffer, lstmTensorInfoScratchBuff, 0, 0);
342 Connect(layer, outputStateOut, lstmTensorInfo3, 1, 0);
343 Connect(layer, cellStateOut, lstmTensorInfo2, 2, 0);
344 Connect(layer, output, lstmTensorInfo3, 3, 0);
346 CreateTensorHandles(graph, factory);
348 // make the workload and check it
349 auto workload = MakeAndCheckWorkload<LstmWorkload>(*layer, graph, factory);
350 LstmQueueDescriptor queueDescriptor = workload->GetData();
351 BOOST_TEST(queueDescriptor.m_Parameters.m_ActivationFunc == 4);
352 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresCell == 0.0f);
353 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresProj == 0.0f);
354 BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
355 BOOST_TEST(queueDescriptor.m_Outputs.size() == 4);
357 BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == TensorInfo({ numUnits, inputSize },
358 DataType::Float32)));
359 BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == TensorInfo({ numUnits },
360 DataType::Float32)));
361 BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == TensorInfo({ numUnits }, DataType::Float32)));
365 template <typename Convolution2dWorkload, armnn::DataType DataType>
366 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
369 // Creates the layer we're testing.
370 Convolution2dDescriptor layerDesc;
371 layerDesc.m_PadLeft = 1;
372 layerDesc.m_PadRight = 1;
373 layerDesc.m_PadTop = 1;
374 layerDesc.m_PadBottom = 1;
375 layerDesc.m_StrideX = 1;
376 layerDesc.m_StrideY = 1;
377 layerDesc.m_BiasEnabled = true;
379 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
381 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
382 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
384 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({ 2, 3, 3, 3 }, DataType, inputsQScale));
385 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>
386 (TensorInfo({2}, GetBiasDataType(DataType), inputsQScale));
387 layer->m_Weight->Allocate();
388 layer->m_Bias->Allocate();
390 // Creates extra layers.
391 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
392 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
395 Connect(input, layer, TensorInfo({2, 3, 6, 6}, DataType, inputsQScale));
396 Connect(layer, output, TensorInfo({2, 2, 6, 6}, DataType, outputQScale));
397 CreateTensorHandles(graph, factory);
399 // Makes the workload and checks it.
400 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
402 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
403 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
404 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
405 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
406 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 1);
407 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
408 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
409 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
411 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
412 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
413 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 3, 3},
414 DataType, inputsQScale)));
415 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo()
416 == TensorInfo({2}, GetBiasDataType(DataType), inputsQScale)));
418 // Returns so we can do extra, backend-specific tests.
422 template <typename DepthwiseConvolution2dFloat32Workload>
423 std::unique_ptr<DepthwiseConvolution2dFloat32Workload> CreateDepthwiseConvolution2dWorkloadTest(
424 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
426 // Creates the layer we're testing.
427 DepthwiseConvolution2dDescriptor layerDesc;
428 layerDesc.m_PadLeft = 3;
429 layerDesc.m_PadRight = 3;
430 layerDesc.m_PadTop = 1;
431 layerDesc.m_PadBottom = 1;
432 layerDesc.m_StrideX = 2;
433 layerDesc.m_StrideY = 4;
434 layerDesc.m_BiasEnabled = true;
436 DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
438 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({3, 3, 5, 3}, DataType::Float32));
439 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({9}, DataType::Float32));
440 layer->m_Weight->Allocate();
441 layer->m_Bias->Allocate();
443 // Creates extra layers.
444 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
445 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
448 Connect(input, layer, TensorInfo({2, 3, 8, 16}, armnn::DataType::Float32));
449 Connect(layer, output, TensorInfo({2, 9, 2, 10}, armnn::DataType::Float32));
450 CreateTensorHandles(graph, factory);
452 // Makes the workload and checks it.
453 auto workload = MakeAndCheckWorkload<DepthwiseConvolution2dFloat32Workload>(*layer, graph, factory);
455 DepthwiseConvolution2dQueueDescriptor queueDescriptor = workload->GetData();
456 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
457 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
458 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
459 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
460 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
461 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
462 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
464 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
465 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
466 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({3, 3, 5, 3}, DataType::Float32)));
467 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({9}, DataType::Float32)));
469 // Returns so we can do extra, backend-specific tests.
473 template <typename FullyConnectedWorkload, armnn::DataType DataType>
474 std::unique_ptr<FullyConnectedWorkload> CreateFullyConnectedWorkloadTest(armnn::IWorkloadFactory& factory,
477 // Creates the layer we're testing.
478 FullyConnectedDescriptor layerDesc;
479 layerDesc.m_BiasEnabled = true;
480 layerDesc.m_TransposeWeightMatrix = true;
482 FullyConnectedLayer* const layer = graph.AddLayer<FullyConnectedLayer>(layerDesc, "layer");
484 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
485 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
487 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7, 20}, DataType, inputsQScale, 0));
488 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7}, GetBiasDataType(DataType), inputsQScale));
489 layer->m_Weight->Allocate();
490 layer->m_Bias->Allocate();
492 // Creates extra layers.
493 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
494 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
497 Connect(input, layer, TensorInfo({3, 1, 4, 5}, DataType, inputsQScale));
498 Connect(layer, output, TensorInfo({3, 7}, DataType, outputQScale));
499 CreateTensorHandles(graph, factory);
501 // Makes the workload and checks it.
502 auto workload = MakeAndCheckWorkload<FullyConnectedWorkload>(*layer, graph, factory);
504 FullyConnectedQueueDescriptor queueDescriptor = workload->GetData();
505 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
506 BOOST_TEST(queueDescriptor.m_Parameters.m_TransposeWeightMatrix == true);
508 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
509 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
510 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({7, 20}, DataType, inputsQScale)));
511 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({7}, GetBiasDataType(DataType), inputsQScale)));
513 // Returns so we can do extra, backend-specific tests.
517 template <typename MultiplicationWorkload, armnn::DataType DataType>
518 std::unique_ptr<MultiplicationWorkload> CreateMultiplicationWorkloadTest(armnn::IWorkloadFactory& factory,
521 // Creates the layer we're testing.
522 Layer* const layer = graph.AddLayer<MultiplicationLayer>("layer");
524 // Creates extra layers.
525 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
526 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
527 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
530 armnn::TensorInfo tensorInfo({2, 3}, DataType);
531 Connect(input1, layer, tensorInfo, 0, 0);
532 Connect(input2, layer, tensorInfo, 0, 1);
533 Connect(layer, output, tensorInfo);
534 CreateTensorHandles(graph, factory);
536 // Makes the workload and checks it.
537 auto workload = MakeAndCheckWorkload<MultiplicationWorkload>(*layer, graph, factory);
539 MultiplicationQueueDescriptor queueDescriptor = workload->GetData();
540 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
541 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
543 // Returns so we can do extra, backend-specific tests.
547 template <typename NormalizationFloat32Workload, armnn::DataType DataType>
548 std::unique_ptr<NormalizationFloat32Workload> CreateNormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
551 // Creates the layer we're testing.
552 NormalizationDescriptor layerDesc;
553 layerDesc.m_NormChannelType = NormalizationAlgorithmChannel::Across;
554 layerDesc.m_NormMethodType = NormalizationAlgorithmMethod::LocalBrightness;
555 layerDesc.m_NormSize = 3;
556 layerDesc.m_Alpha = 0.5f;
557 layerDesc.m_Beta = -1.0f;
558 layerDesc.m_K = 0.2f;
560 NormalizationLayer* layer = graph.AddLayer<NormalizationLayer>(layerDesc, "layer");
562 // Creatse extra layers.
563 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
564 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
567 Connect(input, layer, TensorInfo({3, 5, 5, 1}, DataType));
568 Connect(layer, output, TensorInfo({3, 5, 5, 1}, DataType));
569 CreateTensorHandles(graph, factory);
571 // Makes the workload and checks it.
572 auto workload = MakeAndCheckWorkload<NormalizationFloat32Workload>(*layer, graph, factory);
574 NormalizationQueueDescriptor queueDescriptor = workload->GetData();
575 BOOST_TEST((queueDescriptor.m_Parameters.m_NormChannelType == NormalizationAlgorithmChannel::Across));
576 BOOST_TEST((queueDescriptor.m_Parameters.m_NormMethodType == NormalizationAlgorithmMethod::LocalBrightness));
577 BOOST_TEST(queueDescriptor.m_Parameters.m_NormSize == 3);
578 BOOST_TEST(queueDescriptor.m_Parameters.m_Alpha == 0.5f);
579 BOOST_TEST(queueDescriptor.m_Parameters.m_Beta == -1.0f);
580 BOOST_TEST(queueDescriptor.m_Parameters.m_K == 0.2f);
582 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
583 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
585 // Returns so we can do extra, backend-specific tests.
589 template <typename Pooling2dWorkload, armnn::DataType DataType>
590 std::unique_ptr<Pooling2dWorkload> CreatePooling2dWorkloadTest(armnn::IWorkloadFactory& factory,
593 // Creates the layer we're testing.
594 Pooling2dDescriptor layerDesc;
595 layerDesc.m_PoolType = PoolingAlgorithm::Average;
596 layerDesc.m_PoolWidth = 3;
597 layerDesc.m_PoolHeight = 3;
598 layerDesc.m_PadLeft = 2;
599 layerDesc.m_PadRight = 2;
600 layerDesc.m_PadTop = 1;
601 layerDesc.m_PadBottom = 1;
602 layerDesc.m_StrideX = 2;
603 layerDesc.m_StrideY = 3;
604 layerDesc.m_OutputShapeRounding = OutputShapeRounding::Floor;
606 Pooling2dLayer* const layer = graph.AddLayer<Pooling2dLayer>(layerDesc, "layer");
608 // Create extra layers
609 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
610 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
613 Connect(input, layer, TensorInfo({3, 2, 5, 5}, DataType));
614 Connect(layer, output, TensorInfo({3, 2, 2, 4}, DataType));
615 CreateTensorHandles(graph, factory);
617 // Make the workload and checks it
618 auto workload = MakeAndCheckWorkload<Pooling2dWorkload>(*layer, graph, factory);
620 Pooling2dQueueDescriptor queueDescriptor = workload->GetData();
621 BOOST_TEST((queueDescriptor.m_Parameters.m_PoolType == PoolingAlgorithm::Average));
622 BOOST_TEST((queueDescriptor.m_Parameters.m_OutputShapeRounding == OutputShapeRounding::Floor));
623 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolWidth == 3);
624 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolHeight == 3);
625 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
626 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 3);
627 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 2);
628 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
629 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
630 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
632 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
633 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
635 // Return so we can do extra, backend-specific tests
639 template <typename SoftmaxWorkload, armnn::DataType DataType>
640 std::unique_ptr<SoftmaxWorkload> CreateSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory,
643 // Create the layer we're testing.
644 SoftmaxDescriptor softmaxDescriptor;
645 Layer* const layer = graph.AddLayer<SoftmaxLayer>(softmaxDescriptor, "layer");
647 // Create extra layers.
648 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
649 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
652 armnn::TensorInfo tensorInfo({4, 1}, DataType);
653 Connect(input, layer, tensorInfo);
654 Connect(layer, output, tensorInfo);
655 CreateTensorHandles(graph, factory);
657 // Make the workload and checks it.
658 auto workload = MakeAndCheckWorkload<SoftmaxWorkload>(*layer, graph, factory);
660 SoftmaxQueueDescriptor queueDescriptor = workload->GetData();
661 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
662 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
664 // Return so we can do extra, backend-specific tests.
668 template<typename SplitterWorkload, armnn::DataType DataType>
669 std::unique_ptr<SplitterWorkload>
670 CreateSplitterWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
672 // Create the layer we're testing.
673 // NOTE: need three dimensions channels, height/y, width/x because the Compute
674 // library restricts subtensors to have the same x and y dimensions as
675 // their parent tensors, and therefore the origin on the x and y dimension
676 // has to be zero for any view. So we need a third dimension to split...
677 // NOTE: arguments are: number of views, number of dimensions.
678 ViewsDescriptor layerDesc(3, 3);
679 // NOTE: arguments are: view, dimension, value.
680 layerDesc.SetViewOriginCoord(0, 0, 0);
681 layerDesc.SetViewOriginCoord(1, 0, 1);
682 layerDesc.SetViewOriginCoord(2, 0, 3);
684 Layer* const layer = graph.AddLayer<SplitterLayer>(layerDesc, "layer");
686 // Adds extra layers.
687 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
688 Layer* const output0 = graph.AddLayer<OutputLayer>(0, "output0");
689 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
690 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
693 armnn::TensorInfo tensorInfo({5, 7, 7}, DataType);
694 Connect(input, layer, tensorInfo);
696 armnn::TensorInfo output0Info({1, 7, 7}, DataType);
697 armnn::TensorInfo output1Info({2, 7, 7}, DataType);
698 armnn::TensorInfo output2Info({2, 7, 7}, DataType);
700 Connect(layer, output0, output0Info, 0, 0);
701 Connect(layer, output1, output1Info, 1, 0);
702 Connect(layer, output2, output2Info, 2, 0);
704 CreateTensorHandles(graph, factory);
706 // Makes the workload and checks it.
707 auto workload = MakeAndCheckWorkload<SplitterWorkload>(*layer, graph, factory);
709 SplitterQueueDescriptor queueDescriptor = workload->GetData();
710 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
711 BOOST_TEST(queueDescriptor.m_Outputs.size() == 3);
712 BOOST_TEST(queueDescriptor.m_ViewOrigins.size() == 3);
714 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[0] == 0);
715 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[0] == 1);
716 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[0] == 3);
717 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[1] == 0);
718 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[1] == 0);
719 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[1] == 0);
720 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[2] == 0);
721 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[2] == 0);
722 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[2] == 0);
724 // Returns so we can do extra, backend-specific tests.
728 /// This function constructs a graph with both a splitter and a merger, and returns a pair of the workloads.
729 template<typename SplitterWorkload, typename MergerWorkload, armnn::DataType DataType>
730 std::pair<std::unique_ptr<SplitterWorkload>, std::unique_ptr<MergerWorkload>>
731 CreateSplitterMergerWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
733 armnn::TensorInfo inputTensorInfo({ 1, 2, 100, 10 }, DataType);
735 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 10 }, DataType);
736 armnn::TensorInfo splitTensorInfo2({ 1, 1, 100, 10 }, DataType);
738 //Constructs the graph.
739 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
741 armnn::ViewsDescriptor splitterViews(2);
742 splitterViews.SetViewOriginCoord(0, 0, 0);
743 splitterViews.SetViewOriginCoord(0, 1, 0);
744 splitterViews.SetViewOriginCoord(0, 2, 0);
745 splitterViews.SetViewOriginCoord(0, 3, 0);
747 splitterViews.SetViewOriginCoord(1, 0, 0);
748 splitterViews.SetViewOriginCoord(1, 1, 1);
749 splitterViews.SetViewOriginCoord(1, 2, 0);
750 splitterViews.SetViewOriginCoord(1, 3, 0);
752 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
753 BOOST_TEST_CHECKPOINT("created splitter layer");
755 armnn::OriginsDescriptor mergerViews(2);
756 mergerViews.SetViewOriginCoord(0, 0, 0);
757 mergerViews.SetViewOriginCoord(0, 1, 1);
758 mergerViews.SetViewOriginCoord(0, 2, 0);
759 mergerViews.SetViewOriginCoord(0, 3, 0);
761 mergerViews.SetViewOriginCoord(1, 0, 0);
762 mergerViews.SetViewOriginCoord(1, 1, 0);
763 mergerViews.SetViewOriginCoord(1, 2, 0);
764 mergerViews.SetViewOriginCoord(1, 3, 0);
766 Layer* const merger = graph.AddLayer<MergerLayer>(mergerViews, "merger");
767 BOOST_TEST_CHECKPOINT("created merger layer");
769 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
772 Connect(input, splitter, inputTensorInfo, 0, 0);
773 BOOST_TEST_CHECKPOINT("connect input to splitter");
774 Connect(splitter, merger, splitTensorInfo1, 0, 1); // The splitter & merger are connected up.
775 BOOST_TEST_CHECKPOINT("connect splitter[0] to merger[1]");
776 Connect(splitter, merger, splitTensorInfo2, 1, 0); // So that the outputs are flipped round.
777 BOOST_TEST_CHECKPOINT("connect splitter[1] to merger[0]");
778 Connect(merger, output, inputTensorInfo, 0, 0);
779 BOOST_TEST_CHECKPOINT("connect merger to output");
781 CreateTensorHandles(graph, factory);
782 BOOST_TEST_CHECKPOINT("created tensor handles");
784 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
785 BOOST_TEST_CHECKPOINT("created splitter workload");
786 auto workloadMerger = MakeAndCheckWorkload<MergerWorkload>(*merger, graph, factory);
787 BOOST_TEST_CHECKPOINT("created merger workload");
789 return {std::move(workloadSplitter), std::move(workloadMerger)};
793 /// This function constructs a graph with a splitter with two outputs. Each of the outputs is then
794 /// connected to two different activation layers
795 template<typename SplitterWorkload, typename ActivationWorkload, armnn::DataType DataType>
796 void CreateSplitterMultipleInputsOneOutputWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph,
797 std::unique_ptr<SplitterWorkload>& wlSplitter,
798 std::unique_ptr<ActivationWorkload>& wlActiv0_0,
799 std::unique_ptr<ActivationWorkload>& wlActiv0_1,
800 std::unique_ptr<ActivationWorkload>& wlActiv1_0,
801 std::unique_ptr<ActivationWorkload>& wlActiv1_1)
803 armnn::TensorInfo inputTensorInfo ({ 1, 3, 100, 50 }, DataType);
804 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 50 }, DataType);
805 armnn::TensorInfo splitTensorInfo2({ 1, 2, 100, 50 }, DataType);
807 //Constructs the graph.
808 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
810 armnn::ViewsDescriptor splitterViews(2);
812 splitterViews.SetViewOriginCoord(0, 0, 0);
813 splitterViews.SetViewOriginCoord(0, 1, 0);
814 splitterViews.SetViewOriginCoord(0, 2, 0);
815 splitterViews.SetViewOriginCoord(0, 3, 0);
817 splitterViews.SetViewOriginCoord(1, 0, 0);
818 splitterViews.SetViewOriginCoord(1, 1, 1);
819 splitterViews.SetViewOriginCoord(1, 2, 0);
820 splitterViews.SetViewOriginCoord(1, 3, 0);
822 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
824 armnn::ActivationDescriptor activationDesc;
826 Layer* const activ0_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_0");
827 Layer* const activ0_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_1");
828 Layer* const activ1_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_0");
829 Layer* const activ1_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_1");
831 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
832 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
833 Layer* const output3 = graph.AddLayer<OutputLayer>(3, "output3");
834 Layer* const output4 = graph.AddLayer<OutputLayer>(4, "output4");
837 Connect(input, splitter, inputTensorInfo, 0, 0);
838 Connect(splitter, activ0_0, splitTensorInfo1, 0, 0);
839 Connect(splitter, activ0_1, splitTensorInfo1, 0, 0);
841 Connect(splitter, activ1_0, splitTensorInfo2, 1, 0);
842 Connect(splitter, activ1_1, splitTensorInfo2, 1, 0);
844 Connect(activ0_0, output1, splitTensorInfo1, 0, 0);
845 Connect(activ0_1, output2, splitTensorInfo1, 0, 0);
846 Connect(activ1_0, output3, splitTensorInfo2, 0, 0);
847 Connect(activ1_1, output4, splitTensorInfo2, 0, 0);
849 CreateTensorHandles(graph, factory);
851 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
852 auto workloadActiv0_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_0, graph, factory);
853 auto workloadActiv0_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_1, graph, factory);
854 auto workloadActiv1_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_0, graph, factory);
855 auto workloadActiv1_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_1, graph, factory);
857 wlSplitter = std::move(workloadSplitter);
858 wlActiv0_0 = std::move(workloadActiv0_0);
859 wlActiv0_1 = std::move(workloadActiv0_1);
860 wlActiv1_0 = std::move(workloadActiv1_0);
861 wlActiv1_1 = std::move(workloadActiv1_1);
864 template <typename ResizeBilinearWorkload, armnn::DataType DataType>
865 std::unique_ptr<ResizeBilinearWorkload> CreateResizeBilinearWorkloadTest(armnn::IWorkloadFactory& factory,
868 // Creates the layer we're testing.
869 TensorShape outputShape({ 2, 3, 2, 2 });
870 ResizeBilinearDescriptor resizeDesc;
871 resizeDesc.m_TargetWidth = outputShape[3];
872 resizeDesc.m_TargetHeight = outputShape[2];
873 Layer* const layer = graph.AddLayer<ResizeBilinearLayer>(resizeDesc, "layer");
875 // Creates extra layers.
876 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
877 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
880 armnn::TensorInfo inputTensorInfo({ 2, 3, 4, 4 }, DataType);
881 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
882 Connect(input, layer, inputTensorInfo);
883 Connect(layer, output, outputTensorInfo);
884 CreateTensorHandles(graph, factory);
886 // Makes the workload and checks it.
887 auto workload = MakeAndCheckWorkload<ResizeBilinearWorkload>(*layer, graph, factory);
889 ResizeBilinearQueueDescriptor queueDescriptor = workload->GetData();
890 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
891 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
893 // Returns so we can do extra, backend-specific tests.
897 template <typename L2NormalizationWorkload, armnn::DataType DataType>
898 std::unique_ptr<L2NormalizationWorkload> CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
901 // Creates the layer we're testing.
902 Layer* const layer = graph.AddLayer<L2NormalizationLayer>("l2norm");
904 // Creates extra layers.
905 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
906 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
909 armnn::TensorInfo inputTensorInfo({ 5, 20, 50, 67 }, DataType);
910 armnn::TensorInfo outputTensorInfo({ 5, 20, 50, 67 }, DataType);
911 Connect(input, layer, inputTensorInfo);
912 Connect(layer, output, outputTensorInfo);
913 CreateTensorHandles(graph, factory);
915 // Makes the workload and checks it.
916 auto workload = MakeAndCheckWorkload<L2NormalizationWorkload>(*layer, graph, factory);
918 L2NormalizationQueueDescriptor queueDescriptor = workload->GetData();
919 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
920 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
922 // Returns so we can do extra, backend-specific tests.
926 template <typename ReshapeWorkload, armnn::DataType DataType>
927 std::unique_ptr<ReshapeWorkload> CreateReshapeWorkloadTest(armnn::IWorkloadFactory& factory,
930 // Creates the layer we're testing.
931 TensorShape outputShape({ 1, 4 });
932 ReshapeDescriptor reshapeDesc;
933 reshapeDesc.m_TargetShape = outputShape;
934 Layer* const layer = graph.AddLayer<ReshapeLayer>(reshapeDesc, "layer");
936 // Creates extra layers.
937 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
938 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
941 armnn::TensorInfo inputTensorInfo({ 4, 1 }, DataType);
942 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
943 Connect(input, layer, inputTensorInfo);
944 Connect(layer, output, outputTensorInfo);
945 CreateTensorHandles(graph, factory);
947 // Makes the workload and checks it.
948 auto workload = MakeAndCheckWorkload<ReshapeWorkload>(*layer, graph, factory);
950 ReshapeQueueDescriptor queueDescriptor = workload->GetData();
951 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
952 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
954 // Returns so we can do extra, backend-specific tests.
958 template <typename ConvertFp16ToFp32Float32Workload>
959 std::unique_ptr<ConvertFp16ToFp32Float32Workload> CreateConvertFp16ToFp32WorkloadTest(
960 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
962 // Creates the layer we're testing.
963 ConvertFp16ToFp32Layer* const layer = graph.AddLayer<ConvertFp16ToFp32Layer>("Fp16ToFp32Converter");
965 // Creates extra layers.
966 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
967 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
970 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
971 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
972 Connect(input, layer, inputTensorInfo);
973 Connect(layer, output, outputTensorInfo);
974 CreateTensorHandles(graph, factory);
976 // Makes the workload and checks it.
977 auto workload = MakeAndCheckWorkload<ConvertFp16ToFp32Float32Workload>(*layer, graph, factory);
979 ConvertFp16ToFp32QueueDescriptor queueDescriptor = workload->GetData();
980 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
981 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
983 // Returns so we can do extra, backend-specific tests.
987 template <typename ConvertFp32ToFp16Float16Workload>
988 std::unique_ptr<ConvertFp32ToFp16Float16Workload> CreateConvertFp32ToFp16WorkloadTest(
989 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
991 // Creates the layer we're testing.
992 ConvertFp32ToFp16Layer* const layer = graph.AddLayer<ConvertFp32ToFp16Layer>("Fp32ToFp16Converter");
994 // Creates extra layers.
995 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
996 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
999 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
1000 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
1001 Connect(input, layer, inputTensorInfo);
1002 Connect(layer, output, outputTensorInfo);
1003 CreateTensorHandles(graph, factory);
1005 // Makes the workload and checks it.
1006 auto workload = MakeAndCheckWorkload<ConvertFp32ToFp16Float16Workload>(*layer, graph, factory);
1008 ConvertFp32ToFp16QueueDescriptor queueDescriptor = workload->GetData();
1009 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1010 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1012 // Returns so we can do extra, backend-specific tests.