IVGCVSW-1801 : Cl implementation for SUB
[platform/upstream/armnn.git] / src / armnn / test / CreateWorkload.hpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6
7 #include <boost/test/unit_test.hpp>
8
9 #include <boost/cast.hpp>
10
11 #include "backends/WorkloadData.hpp"
12 #include "Graph.hpp"
13
14 #include <utility>
15
16 #include "backends/CpuTensorHandle.hpp"
17
18 using namespace armnn;
19
20 namespace
21 {
22
23 using namespace std;
24
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)
28 {
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()));
36 }
37
38 // Connects two layers.
39 void Connect(Layer* from, Layer* to, const TensorInfo& tensorInfo, unsigned int fromIndex = 0, unsigned int toIndex = 0)
40 {
41     from->GetOutputSlot(fromIndex).Connect(to->GetInputSlot(toIndex));
42     from->GetOutputHandler(fromIndex).SetTensorInfo(tensorInfo);
43 }
44
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)
47 {
48     for (auto&& layer : graph.TopologicalSort())
49     {
50         layer->CreateTensorHandles(graph, factory);
51     }
52 }
53
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 /////////////////////////////////////////////////////////////////////////////////////////////
60
61 template <typename ActivationWorkload, armnn::DataType DataType>
62 std::unique_ptr<ActivationWorkload> CreateActivationWorkloadTest(armnn::IWorkloadFactory& factory,
63                                                                  armnn::Graph&            graph)
64 {
65     // Creates the layer we're testing.
66     ActivationDescriptor layerDesc;
67     layerDesc.m_Function = ActivationFunction::Abs;
68     layerDesc.m_A        = 3.5f;
69     layerDesc.m_B        = -10.0f;
70
71     ActivationLayer* const layer = graph.AddLayer<ActivationLayer>(layerDesc, "layer");
72
73     // Creates extra layers.
74     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
75     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
76
77     // Connects up.
78     armnn::TensorInfo tensorInfo({1, 1}, DataType);
79
80     Connect(input, layer, tensorInfo);
81     Connect(layer, output, tensorInfo);
82
83     CreateTensorHandles(graph, factory);
84
85     // Makes the workload and checks it.
86     auto workload = MakeAndCheckWorkload<ActivationWorkload>(*layer, graph, factory);
87
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));
94
95     // Returns so we can do extra, backend-specific tests.
96     return workload;
97 }
98
99 template <typename AdditionWorkload, armnn::DataType DataType>
100 std::unique_ptr<AdditionWorkload> CreateAdditionWorkloadTest(armnn::IWorkloadFactory& factory,
101                                                              armnn::Graph&            graph)
102 {
103     // Creates the layer we're testing.
104     Layer* const layer = graph.AddLayer<AdditionLayer>("layer");
105
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");
110
111     // Connects up.
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);
117
118     // Makes the workload and checks it.
119     auto workload = MakeAndCheckWorkload<AdditionWorkload>(*layer, graph, factory);
120
121     AdditionQueueDescriptor queueDescriptor = workload->GetData();
122     BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
123     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
124
125     // Returns so we can do extra, backend-specific tests.
126     return workload;
127 }
128
129 template <typename WorkloadType,
130           typename DescriptorType,
131           typename LayerType,
132           armnn::DataType DataType>
133 std::unique_ptr<WorkloadType> CreateArithmeticWorkloadTest(armnn::IWorkloadFactory& factory,
134                                                            armnn::Graph&            graph)
135 {
136     // Creates the layer we're testing.
137     Layer* const layer = graph.AddLayer<LayerType>("layer");
138
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");
143
144     // Connects up.
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);
150
151     // Makes the workload and checks it.
152     auto workload = MakeAndCheckWorkload<WorkloadType>(*layer, graph, factory);
153
154     DescriptorType queueDescriptor = workload->GetData();
155     BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
156     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
157
158     // Returns so we can do extra, backend-specific tests.
159     return workload;
160 }
161
162 template <typename BatchNormalizationFloat32Workload, armnn::DataType DataType>
163 std::unique_ptr<BatchNormalizationFloat32Workload> CreateBatchNormalizationWorkloadTest(
164     armnn::IWorkloadFactory& factory, armnn::Graph& graph)
165 {
166     // Creates the layer we're testing.
167     BatchNormalizationDescriptor layerDesc;
168     layerDesc.m_Eps = 0.05f;
169
170     BatchNormalizationLayer* const layer = graph.AddLayer<BatchNormalizationLayer>(layerDesc, "layer");
171
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();
181
182     // Creates extra layers.
183     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
184     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
185
186     // Connects up.
187     armnn::TensorInfo tensorInfo({2, 3, 1, 1}, DataType);
188     Connect(input, layer, tensorInfo);
189     Connect(layer, output, tensorInfo);
190     CreateTensorHandles(graph, factory);
191
192     // Makes the workload and checks it.
193     auto workload = MakeAndCheckWorkload<BatchNormalizationFloat32Workload>(*layer, graph, factory);
194
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)));
203
204     // Returns so we can do extra, backend-specific tests.
205     return workload;
206 }
207
208 template <typename Convolution2dWorkload, armnn::DataType DataType>
209 std::unique_ptr<Convolution2dWorkload> CreateConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
210                                                                               armnn::Graph&            graph)
211 {
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;
221
222     Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
223
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)));
226
227     layer->m_Weight->Allocate();
228     layer->m_Bias->Allocate();
229
230     // Creates extra layers.
231     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
232     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
233
234     // Connecst up.
235     Connect(input, layer, TensorInfo({2, 3, 8, 16}, DataType));
236     Connect(layer, output, TensorInfo({2, 2, 2, 10}, DataType));
237     CreateTensorHandles(graph, factory);
238
239     // Makes the workload and checks it.
240     auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
241
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);
250
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))));
256
257     // Returns so we can do extra, backend-specific tests.
258     return workload;
259 }
260
261 template <typename LstmWorkload>
262 std::unique_ptr<LstmWorkload> CreateLstmWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
263 {
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;
272
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;
278
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));
297
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();
307
308
309     if (layerDesc.m_PeepholeEnabled)
310     {
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();
317     }
318
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");
327
328     // connect up
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)
334     {
335         lstmTensorInfoScratchBuff.SetShape({ batchSize, numUnits*4 });
336     }
337
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);
345
346     CreateTensorHandles(graph, factory);
347
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);
356
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)));
362     return workload;
363 }
364
365 template <typename Convolution2dWorkload, armnn::DataType DataType>
366 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
367                                                                        armnn::Graph&            graph)
368 {
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;
378
379     Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
380
381     float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
382     float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
383
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();
389
390     // Creates extra layers.
391     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
392     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
393
394     // Connects up.
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);
398
399     // Makes the workload and checks it.
400     auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
401
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);
410
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)));
417
418     // Returns so we can do extra, backend-specific tests.
419     return workload;
420 }
421
422 template <typename DepthwiseConvolution2dFloat32Workload>
423 std::unique_ptr<DepthwiseConvolution2dFloat32Workload> CreateDepthwiseConvolution2dWorkloadTest(
424     armnn::IWorkloadFactory& factory, armnn::Graph& graph)
425 {
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;
435
436     DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
437
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();
442
443     // Creates extra layers.
444     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
445     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
446
447     // Connects up.
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);
451
452     // Makes the workload and checks it.
453     auto workload = MakeAndCheckWorkload<DepthwiseConvolution2dFloat32Workload>(*layer, graph, factory);
454
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);
463
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)));
468
469     // Returns so we can do extra, backend-specific tests.
470     return workload;
471 }
472
473 template <typename FullyConnectedWorkload, armnn::DataType DataType>
474 std::unique_ptr<FullyConnectedWorkload> CreateFullyConnectedWorkloadTest(armnn::IWorkloadFactory& factory,
475                                                                          armnn::Graph&            graph)
476 {
477     // Creates the layer we're testing.
478     FullyConnectedDescriptor layerDesc;
479     layerDesc.m_BiasEnabled = true;
480     layerDesc.m_TransposeWeightMatrix = true;
481
482     FullyConnectedLayer* const layer = graph.AddLayer<FullyConnectedLayer>(layerDesc, "layer");
483
484     float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
485     float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
486
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();
491
492     // Creates extra layers.
493     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
494     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
495
496     // Connects up.
497     Connect(input, layer, TensorInfo({3, 1, 4, 5}, DataType, inputsQScale));
498     Connect(layer, output, TensorInfo({3, 7}, DataType, outputQScale));
499     CreateTensorHandles(graph, factory);
500
501     // Makes the workload and checks it.
502     auto workload = MakeAndCheckWorkload<FullyConnectedWorkload>(*layer, graph, factory);
503
504     FullyConnectedQueueDescriptor queueDescriptor = workload->GetData();
505     BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
506     BOOST_TEST(queueDescriptor.m_Parameters.m_TransposeWeightMatrix == true);
507
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)));
512
513     // Returns so we can do extra, backend-specific tests.
514     return workload;
515 }
516
517 template <typename MultiplicationWorkload, armnn::DataType DataType>
518 std::unique_ptr<MultiplicationWorkload> CreateMultiplicationWorkloadTest(armnn::IWorkloadFactory& factory,
519                                                                          armnn::Graph&            graph)
520 {
521     // Creates the layer we're testing.
522     Layer* const layer = graph.AddLayer<MultiplicationLayer>("layer");
523
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");
528
529     // Connects up.
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);
535
536     // Makes the workload and checks it.
537     auto workload = MakeAndCheckWorkload<MultiplicationWorkload>(*layer, graph, factory);
538
539     MultiplicationQueueDescriptor queueDescriptor = workload->GetData();
540     BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
541     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
542
543     // Returns so we can do extra, backend-specific tests.
544     return workload;
545 }
546
547 template <typename NormalizationFloat32Workload, armnn::DataType DataType>
548 std::unique_ptr<NormalizationFloat32Workload> CreateNormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
549                                                                               armnn::Graph&            graph)
550 {
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;
559
560     NormalizationLayer* layer = graph.AddLayer<NormalizationLayer>(layerDesc, "layer");
561
562     // Creatse extra layers.
563     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
564     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
565
566     // Connects up.
567     Connect(input, layer, TensorInfo({3, 5, 5, 1}, DataType));
568     Connect(layer, output, TensorInfo({3, 5, 5, 1}, DataType));
569     CreateTensorHandles(graph, factory);
570
571     // Makes the workload and checks it.
572     auto workload = MakeAndCheckWorkload<NormalizationFloat32Workload>(*layer, graph, factory);
573
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);
581
582     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
583     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
584
585     // Returns so we can do extra, backend-specific tests.
586     return workload;
587 }
588
589 template <typename Pooling2dWorkload, armnn::DataType DataType>
590 std::unique_ptr<Pooling2dWorkload> CreatePooling2dWorkloadTest(armnn::IWorkloadFactory& factory,
591                                                                armnn::Graph&            graph)
592 {
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;
605
606     Pooling2dLayer* const layer = graph.AddLayer<Pooling2dLayer>(layerDesc, "layer");
607
608     // Create extra layers
609     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
610     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
611
612     // Connect up
613     Connect(input, layer, TensorInfo({3, 2, 5, 5}, DataType));
614     Connect(layer, output, TensorInfo({3, 2, 2, 4}, DataType));
615     CreateTensorHandles(graph, factory);
616
617     // Make the workload and checks it
618     auto workload = MakeAndCheckWorkload<Pooling2dWorkload>(*layer, graph, factory);
619
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);
631
632     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
633     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
634
635     // Return so we can do extra, backend-specific tests
636     return workload;
637 }
638
639 template <typename SoftmaxWorkload, armnn::DataType DataType>
640 std::unique_ptr<SoftmaxWorkload> CreateSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory,
641                                                            armnn::Graph&            graph)
642 {
643     // Create the layer we're testing.
644     SoftmaxDescriptor softmaxDescriptor;
645     Layer* const layer = graph.AddLayer<SoftmaxLayer>(softmaxDescriptor, "layer");
646
647     // Create extra layers.
648     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
649     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
650
651     // Connect up
652     armnn::TensorInfo tensorInfo({4, 1}, DataType);
653     Connect(input, layer, tensorInfo);
654     Connect(layer, output, tensorInfo);
655     CreateTensorHandles(graph, factory);
656
657     // Make the workload and checks it.
658     auto workload = MakeAndCheckWorkload<SoftmaxWorkload>(*layer, graph, factory);
659
660     SoftmaxQueueDescriptor queueDescriptor = workload->GetData();
661     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
662     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
663
664     // Return so we can do extra, backend-specific tests.
665     return workload;
666 }
667
668 template<typename SplitterWorkload, armnn::DataType DataType>
669 std::unique_ptr<SplitterWorkload>
670     CreateSplitterWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
671 {
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);
683
684     Layer* const layer = graph.AddLayer<SplitterLayer>(layerDesc, "layer");
685
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");
691
692     // Connects up.
693     armnn::TensorInfo tensorInfo({5, 7, 7}, DataType);
694     Connect(input, layer, tensorInfo);
695
696     armnn::TensorInfo output0Info({1, 7, 7}, DataType);
697     armnn::TensorInfo output1Info({2, 7, 7}, DataType);
698     armnn::TensorInfo output2Info({2, 7, 7}, DataType);
699
700     Connect(layer, output0, output0Info, 0, 0);
701     Connect(layer, output1, output1Info, 1, 0);
702     Connect(layer, output2, output2Info, 2, 0);
703
704     CreateTensorHandles(graph, factory);
705
706     // Makes the workload and checks it.
707     auto workload = MakeAndCheckWorkload<SplitterWorkload>(*layer, graph, factory);
708
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);
713
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);
723
724     // Returns so we can do extra, backend-specific tests.
725     return workload;
726 }
727
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)
732 {
733     armnn::TensorInfo inputTensorInfo({ 1, 2, 100, 10 }, DataType);
734
735     armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 10 }, DataType);
736     armnn::TensorInfo splitTensorInfo2({ 1, 1, 100, 10 }, DataType);
737
738     //Constructs the graph.
739     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
740
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);
746
747     splitterViews.SetViewOriginCoord(1, 0, 0);
748     splitterViews.SetViewOriginCoord(1, 1, 1);
749     splitterViews.SetViewOriginCoord(1, 2, 0);
750     splitterViews.SetViewOriginCoord(1, 3, 0);
751
752     Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
753     BOOST_TEST_CHECKPOINT("created splitter layer");
754
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);
760
761     mergerViews.SetViewOriginCoord(1, 0, 0);
762     mergerViews.SetViewOriginCoord(1, 1, 0);
763     mergerViews.SetViewOriginCoord(1, 2, 0);
764     mergerViews.SetViewOriginCoord(1, 3, 0);
765
766     Layer* const merger = graph.AddLayer<MergerLayer>(mergerViews, "merger");
767     BOOST_TEST_CHECKPOINT("created merger layer");
768
769     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
770
771     // Adds connections.
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");
780
781     CreateTensorHandles(graph, factory);
782     BOOST_TEST_CHECKPOINT("created tensor handles");
783
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");
788
789     return {std::move(workloadSplitter), std::move(workloadMerger)};
790 }
791
792
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)
802 {
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);
806
807     //Constructs the graph.
808     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
809
810     armnn::ViewsDescriptor splitterViews(2);
811
812     splitterViews.SetViewOriginCoord(0, 0, 0);
813     splitterViews.SetViewOriginCoord(0, 1, 0);
814     splitterViews.SetViewOriginCoord(0, 2, 0);
815     splitterViews.SetViewOriginCoord(0, 3, 0);
816
817     splitterViews.SetViewOriginCoord(1, 0, 0);
818     splitterViews.SetViewOriginCoord(1, 1, 1);
819     splitterViews.SetViewOriginCoord(1, 2, 0);
820     splitterViews.SetViewOriginCoord(1, 3, 0);
821
822     Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
823
824     armnn::ActivationDescriptor activationDesc;
825
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");
830
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");
835
836     // Adds connections.
837     Connect(input, splitter, inputTensorInfo, 0, 0);
838     Connect(splitter, activ0_0, splitTensorInfo1, 0, 0);
839     Connect(splitter, activ0_1, splitTensorInfo1, 0, 0);
840
841     Connect(splitter, activ1_0, splitTensorInfo2, 1, 0);
842     Connect(splitter, activ1_1, splitTensorInfo2, 1, 0);
843
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);
848
849     CreateTensorHandles(graph, factory);
850
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);
856
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);
862 }
863
864 template <typename ResizeBilinearWorkload, armnn::DataType DataType>
865 std::unique_ptr<ResizeBilinearWorkload> CreateResizeBilinearWorkloadTest(armnn::IWorkloadFactory& factory,
866     armnn::Graph& graph)
867 {
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");
874
875     // Creates extra layers.
876     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
877     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
878
879     // Connects up.
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);
885
886     // Makes the workload and checks it.
887     auto workload = MakeAndCheckWorkload<ResizeBilinearWorkload>(*layer, graph, factory);
888
889     ResizeBilinearQueueDescriptor queueDescriptor = workload->GetData();
890     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
891     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
892
893     // Returns so we can do extra, backend-specific tests.
894     return workload;
895 }
896
897 template <typename L2NormalizationWorkload, armnn::DataType DataType>
898 std::unique_ptr<L2NormalizationWorkload> CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
899     armnn::Graph& graph)
900 {
901     // Creates the layer we're testing.
902     Layer* const layer = graph.AddLayer<L2NormalizationLayer>("l2norm");
903
904     // Creates extra layers.
905     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
906     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
907
908     // Connects up.
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);
914
915     // Makes the workload and checks it.
916     auto workload = MakeAndCheckWorkload<L2NormalizationWorkload>(*layer, graph, factory);
917
918     L2NormalizationQueueDescriptor queueDescriptor = workload->GetData();
919     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
920     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
921
922     // Returns so we can do extra, backend-specific tests.
923     return workload;
924 }
925
926 template <typename ReshapeWorkload, armnn::DataType DataType>
927 std::unique_ptr<ReshapeWorkload> CreateReshapeWorkloadTest(armnn::IWorkloadFactory& factory,
928     armnn::Graph& graph)
929 {
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");
935
936     // Creates extra layers.
937     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
938     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
939
940     // Connects up.
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);
946
947     // Makes the workload and checks it.
948     auto workload = MakeAndCheckWorkload<ReshapeWorkload>(*layer, graph, factory);
949
950     ReshapeQueueDescriptor queueDescriptor = workload->GetData();
951     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
952     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
953
954     // Returns so we can do extra, backend-specific tests.
955     return workload;
956 }
957
958 template <typename ConvertFp16ToFp32Float32Workload>
959 std::unique_ptr<ConvertFp16ToFp32Float32Workload> CreateConvertFp16ToFp32WorkloadTest(
960     armnn::IWorkloadFactory& factory, armnn::Graph& graph)
961 {
962     // Creates the layer we're testing.
963     ConvertFp16ToFp32Layer* const layer = graph.AddLayer<ConvertFp16ToFp32Layer>("Fp16ToFp32Converter");
964
965     // Creates extra layers.
966     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
967     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
968
969     // Connects up.
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);
975
976     // Makes the workload and checks it.
977     auto workload = MakeAndCheckWorkload<ConvertFp16ToFp32Float32Workload>(*layer, graph, factory);
978
979     ConvertFp16ToFp32QueueDescriptor queueDescriptor = workload->GetData();
980     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
981     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
982
983     // Returns so we can do extra, backend-specific tests.
984     return workload;
985 }
986
987 template <typename ConvertFp32ToFp16Float16Workload>
988 std::unique_ptr<ConvertFp32ToFp16Float16Workload> CreateConvertFp32ToFp16WorkloadTest(
989     armnn::IWorkloadFactory& factory, armnn::Graph& graph)
990 {
991     // Creates the layer we're testing.
992     ConvertFp32ToFp16Layer* const layer = graph.AddLayer<ConvertFp32ToFp16Layer>("Fp32ToFp16Converter");
993
994     // Creates extra layers.
995     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
996     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
997
998     // Connects up.
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);
1004
1005     // Makes the workload and checks it.
1006     auto workload = MakeAndCheckWorkload<ConvertFp32ToFp16Float16Workload>(*layer, graph, factory);
1007
1008     ConvertFp32ToFp16QueueDescriptor queueDescriptor = workload->GetData();
1009     BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1010     BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1011
1012     // Returns so we can do extra, backend-specific tests.
1013     return workload;
1014 }
1015
1016 }