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 WorkloadType,
100 typename DescriptorType,
102 armnn::DataType DataType>
103 std::unique_ptr<WorkloadType> CreateArithmeticWorkloadTest(armnn::IWorkloadFactory& factory,
106 // Creates the layer we're testing.
107 Layer* const layer = graph.AddLayer<LayerType>("layer");
109 // Creates extra layers.
110 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
111 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
112 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
115 armnn::TensorInfo tensorInfo({2, 3}, DataType);
116 Connect(input1, layer, tensorInfo, 0, 0);
117 Connect(input2, layer, tensorInfo, 0, 1);
118 Connect(layer, output, tensorInfo);
119 CreateTensorHandles(graph, factory);
121 // Makes the workload and checks it.
122 auto workload = MakeAndCheckWorkload<WorkloadType>(*layer, graph, factory);
124 DescriptorType queueDescriptor = workload->GetData();
125 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
126 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
128 // Returns so we can do extra, backend-specific tests.
132 template <typename BatchNormalizationFloat32Workload, armnn::DataType DataType>
133 std::unique_ptr<BatchNormalizationFloat32Workload> CreateBatchNormalizationWorkloadTest(
134 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
136 // Creates the layer we're testing.
137 BatchNormalizationDescriptor layerDesc;
138 layerDesc.m_Eps = 0.05f;
140 BatchNormalizationLayer* const layer = graph.AddLayer<BatchNormalizationLayer>(layerDesc, "layer");
142 armnn::TensorInfo weightInfo({3}, DataType);
143 layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
144 layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
145 layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
146 layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
147 layer->m_Mean->Allocate();
148 layer->m_Variance->Allocate();
149 layer->m_Beta->Allocate();
150 layer->m_Gamma->Allocate();
152 // Creates extra layers.
153 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
154 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
157 armnn::TensorInfo tensorInfo({2, 3, 1, 1}, DataType);
158 Connect(input, layer, tensorInfo);
159 Connect(layer, output, tensorInfo);
160 CreateTensorHandles(graph, factory);
162 // Makes the workload and checks it.
163 auto workload = MakeAndCheckWorkload<BatchNormalizationFloat32Workload>(*layer, graph, factory);
165 BatchNormalizationQueueDescriptor queueDescriptor = workload->GetData();
166 BOOST_TEST(queueDescriptor.m_Parameters.m_Eps == 0.05f);
167 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
168 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
169 BOOST_TEST((queueDescriptor.m_Mean->GetTensorInfo() == TensorInfo({3}, DataType)));
170 BOOST_TEST((queueDescriptor.m_Variance->GetTensorInfo() == TensorInfo({3}, DataType)));
171 BOOST_TEST((queueDescriptor.m_Gamma->GetTensorInfo() == TensorInfo({3}, DataType)));
172 BOOST_TEST((queueDescriptor.m_Beta->GetTensorInfo() == TensorInfo({3}, DataType)));
174 // Returns so we can do extra, backend-specific tests.
178 template <typename Convolution2dWorkload, armnn::DataType DataType>
179 std::unique_ptr<Convolution2dWorkload> CreateConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
182 // Creates the layer we're testing.
183 Convolution2dDescriptor layerDesc;
184 layerDesc.m_PadLeft = 3;
185 layerDesc.m_PadRight = 3;
186 layerDesc.m_PadTop = 1;
187 layerDesc.m_PadBottom = 1;
188 layerDesc.m_StrideX = 2;
189 layerDesc.m_StrideY = 4;
190 layerDesc.m_BiasEnabled = true;
192 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
194 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2, 3, 5, 3}, DataType));
195 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
197 layer->m_Weight->Allocate();
198 layer->m_Bias->Allocate();
200 // Creates extra layers.
201 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
202 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
205 Connect(input, layer, TensorInfo({2, 3, 8, 16}, DataType));
206 Connect(layer, output, TensorInfo({2, 2, 2, 10}, DataType));
207 CreateTensorHandles(graph, factory);
209 // Makes the workload and checks it.
210 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
212 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
213 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
214 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
215 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
216 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
217 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
218 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
219 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
221 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
222 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
223 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 5, 3}, DataType)));
224 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() ==
225 TensorInfo({2}, GetBiasDataType(DataType))));
227 // Returns so we can do extra, backend-specific tests.
231 template <typename LstmWorkload>
232 std::unique_ptr<LstmWorkload> CreateLstmWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
234 // This parameter setting is for withCifgWithPeepholeNoProjection
235 LstmDescriptor layerDesc;
236 layerDesc.m_ActivationFunc = 4;
237 layerDesc.m_ClippingThresCell = 0.0f;
238 layerDesc.m_ClippingThresProj = 0.0f;
239 layerDesc.m_CifgEnabled = true;
240 layerDesc.m_PeepholeEnabled = true;
241 layerDesc.m_ProjectionEnabled = false;
243 LstmLayer* const layer = graph.AddLayer<LstmLayer>(layerDesc, "layer");
244 unsigned int batchSize = 2;
245 unsigned int inputSize = 2;
246 unsigned int numUnits = 4;
247 unsigned int outputSize = 4;
249 layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
250 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
251 layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>
252 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
253 layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
254 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
255 layer->m_BasicParameters.m_RecurrentToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
256 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
257 layer->m_BasicParameters.m_RecurrentToCellWeights = std::make_unique<ScopedCpuTensorHandle>
258 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
259 layer->m_BasicParameters.m_RecurrentToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
260 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
261 layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>
262 (TensorInfo({ numUnits }, DataType::Float32));
263 layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>
264 (TensorInfo({ numUnits }, DataType::Float32));
265 layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>
266 (TensorInfo({ numUnits }, DataType::Float32));
268 layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
269 layer->m_BasicParameters.m_InputToCellWeights->Allocate();
270 layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
271 layer->m_BasicParameters.m_RecurrentToForgetWeights->Allocate();
272 layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
273 layer->m_BasicParameters.m_RecurrentToOutputWeights->Allocate();
274 layer->m_BasicParameters.m_ForgetGateBias->Allocate();
275 layer->m_BasicParameters.m_CellBias->Allocate();
276 layer->m_BasicParameters.m_OutputGateBias->Allocate();
279 if (layerDesc.m_PeepholeEnabled)
281 layer->m_PeepholeParameters.m_CellToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
282 (TensorInfo({ numUnits }, DataType::Float32));
283 layer->m_PeepholeParameters.m_CellToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
284 (TensorInfo({ numUnits }, DataType::Float32));
285 layer->m_PeepholeParameters.m_CellToForgetWeights->Allocate();
286 layer->m_PeepholeParameters.m_CellToOutputWeights->Allocate();
289 // create input and output layers
290 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
291 Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
292 Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
293 Layer* const scratchBuffer = graph.AddLayer<OutputLayer>(0, "scratchBuffer");
294 Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
295 Layer* const cellStateOut = graph.AddLayer<OutputLayer>(2, "cellStateOut");
296 Layer* const output = graph.AddLayer<OutputLayer>(3, "output");
299 armnn::TensorInfo lstmTensorInfo1({ batchSize, inputSize }, DataType::Float32);
300 armnn::TensorInfo lstmTensorInfo2({ batchSize, numUnits}, DataType::Float32);
301 armnn::TensorInfo lstmTensorInfo3({ batchSize, outputSize }, DataType::Float32);
302 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits*3 }, DataType::Float32);
303 if (layerDesc.m_CifgEnabled)
305 lstmTensorInfoScratchBuff.SetShape({ batchSize, numUnits*4 });
308 Connect(input, layer, lstmTensorInfo1, 0, 0);
309 Connect(cellStateIn, layer, lstmTensorInfo2, 0, 1);
310 Connect(outputStateIn, layer, lstmTensorInfo3, 0, 2);
311 Connect(layer, scratchBuffer, lstmTensorInfoScratchBuff, 0, 0);
312 Connect(layer, outputStateOut, lstmTensorInfo3, 1, 0);
313 Connect(layer, cellStateOut, lstmTensorInfo2, 2, 0);
314 Connect(layer, output, lstmTensorInfo3, 3, 0);
316 CreateTensorHandles(graph, factory);
318 // make the workload and check it
319 auto workload = MakeAndCheckWorkload<LstmWorkload>(*layer, graph, factory);
320 LstmQueueDescriptor queueDescriptor = workload->GetData();
321 BOOST_TEST(queueDescriptor.m_Parameters.m_ActivationFunc == 4);
322 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresCell == 0.0f);
323 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresProj == 0.0f);
324 BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
325 BOOST_TEST(queueDescriptor.m_Outputs.size() == 4);
327 BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == TensorInfo({ numUnits, inputSize },
328 DataType::Float32)));
329 BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == TensorInfo({ numUnits },
330 DataType::Float32)));
331 BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == TensorInfo({ numUnits }, DataType::Float32)));
335 template <typename Convolution2dWorkload, armnn::DataType DataType>
336 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
339 // Creates the layer we're testing.
340 Convolution2dDescriptor layerDesc;
341 layerDesc.m_PadLeft = 1;
342 layerDesc.m_PadRight = 1;
343 layerDesc.m_PadTop = 1;
344 layerDesc.m_PadBottom = 1;
345 layerDesc.m_StrideX = 1;
346 layerDesc.m_StrideY = 1;
347 layerDesc.m_BiasEnabled = true;
349 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
351 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
352 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
354 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({ 2, 3, 3, 3 }, DataType, inputsQScale));
355 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>
356 (TensorInfo({2}, GetBiasDataType(DataType), inputsQScale));
357 layer->m_Weight->Allocate();
358 layer->m_Bias->Allocate();
360 // Creates extra layers.
361 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
362 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
365 Connect(input, layer, TensorInfo({2, 3, 6, 6}, DataType, inputsQScale));
366 Connect(layer, output, TensorInfo({2, 2, 6, 6}, DataType, outputQScale));
367 CreateTensorHandles(graph, factory);
369 // Makes the workload and checks it.
370 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
372 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
373 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
374 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
375 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
376 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 1);
377 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
378 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
379 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
381 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
382 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
383 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 3, 3},
384 DataType, inputsQScale)));
385 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo()
386 == TensorInfo({2}, GetBiasDataType(DataType), inputsQScale)));
388 // Returns so we can do extra, backend-specific tests.
392 template <typename DepthwiseConvolution2dFloat32Workload>
393 std::unique_ptr<DepthwiseConvolution2dFloat32Workload> CreateDepthwiseConvolution2dWorkloadTest(
394 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
396 // Creates the layer we're testing.
397 DepthwiseConvolution2dDescriptor layerDesc;
398 layerDesc.m_PadLeft = 3;
399 layerDesc.m_PadRight = 3;
400 layerDesc.m_PadTop = 1;
401 layerDesc.m_PadBottom = 1;
402 layerDesc.m_StrideX = 2;
403 layerDesc.m_StrideY = 4;
404 layerDesc.m_BiasEnabled = true;
406 DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
408 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({3, 3, 5, 3}, DataType::Float32));
409 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({9}, DataType::Float32));
410 layer->m_Weight->Allocate();
411 layer->m_Bias->Allocate();
413 // Creates extra layers.
414 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
415 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
418 Connect(input, layer, TensorInfo({2, 3, 8, 16}, armnn::DataType::Float32));
419 Connect(layer, output, TensorInfo({2, 9, 2, 10}, armnn::DataType::Float32));
420 CreateTensorHandles(graph, factory);
422 // Makes the workload and checks it.
423 auto workload = MakeAndCheckWorkload<DepthwiseConvolution2dFloat32Workload>(*layer, graph, factory);
425 DepthwiseConvolution2dQueueDescriptor queueDescriptor = workload->GetData();
426 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
427 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
428 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
429 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
430 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
431 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
432 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
434 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
435 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
436 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({3, 3, 5, 3}, DataType::Float32)));
437 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({9}, DataType::Float32)));
439 // Returns so we can do extra, backend-specific tests.
443 template <typename FullyConnectedWorkload, armnn::DataType DataType>
444 std::unique_ptr<FullyConnectedWorkload> CreateFullyConnectedWorkloadTest(armnn::IWorkloadFactory& factory,
447 // Creates the layer we're testing.
448 FullyConnectedDescriptor layerDesc;
449 layerDesc.m_BiasEnabled = true;
450 layerDesc.m_TransposeWeightMatrix = true;
452 FullyConnectedLayer* const layer = graph.AddLayer<FullyConnectedLayer>(layerDesc, "layer");
454 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
455 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
457 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7, 20}, DataType, inputsQScale, 0));
458 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7}, GetBiasDataType(DataType), inputsQScale));
459 layer->m_Weight->Allocate();
460 layer->m_Bias->Allocate();
462 // Creates extra layers.
463 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
464 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
467 Connect(input, layer, TensorInfo({3, 1, 4, 5}, DataType, inputsQScale));
468 Connect(layer, output, TensorInfo({3, 7}, DataType, outputQScale));
469 CreateTensorHandles(graph, factory);
471 // Makes the workload and checks it.
472 auto workload = MakeAndCheckWorkload<FullyConnectedWorkload>(*layer, graph, factory);
474 FullyConnectedQueueDescriptor queueDescriptor = workload->GetData();
475 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
476 BOOST_TEST(queueDescriptor.m_Parameters.m_TransposeWeightMatrix == true);
478 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
479 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
480 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({7, 20}, DataType, inputsQScale)));
481 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({7}, GetBiasDataType(DataType), inputsQScale)));
483 // Returns so we can do extra, backend-specific tests.
487 template <typename NormalizationFloat32Workload, armnn::DataType DataType>
488 std::unique_ptr<NormalizationFloat32Workload> CreateNormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
491 // Creates the layer we're testing.
492 NormalizationDescriptor layerDesc;
493 layerDesc.m_NormChannelType = NormalizationAlgorithmChannel::Across;
494 layerDesc.m_NormMethodType = NormalizationAlgorithmMethod::LocalBrightness;
495 layerDesc.m_NormSize = 3;
496 layerDesc.m_Alpha = 0.5f;
497 layerDesc.m_Beta = -1.0f;
498 layerDesc.m_K = 0.2f;
500 NormalizationLayer* layer = graph.AddLayer<NormalizationLayer>(layerDesc, "layer");
502 // Creatse extra layers.
503 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
504 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
507 Connect(input, layer, TensorInfo({3, 5, 5, 1}, DataType));
508 Connect(layer, output, TensorInfo({3, 5, 5, 1}, DataType));
509 CreateTensorHandles(graph, factory);
511 // Makes the workload and checks it.
512 auto workload = MakeAndCheckWorkload<NormalizationFloat32Workload>(*layer, graph, factory);
514 NormalizationQueueDescriptor queueDescriptor = workload->GetData();
515 BOOST_TEST((queueDescriptor.m_Parameters.m_NormChannelType == NormalizationAlgorithmChannel::Across));
516 BOOST_TEST((queueDescriptor.m_Parameters.m_NormMethodType == NormalizationAlgorithmMethod::LocalBrightness));
517 BOOST_TEST(queueDescriptor.m_Parameters.m_NormSize == 3);
518 BOOST_TEST(queueDescriptor.m_Parameters.m_Alpha == 0.5f);
519 BOOST_TEST(queueDescriptor.m_Parameters.m_Beta == -1.0f);
520 BOOST_TEST(queueDescriptor.m_Parameters.m_K == 0.2f);
522 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
523 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
525 // Returns so we can do extra, backend-specific tests.
529 template <typename Pooling2dWorkload, armnn::DataType DataType>
530 std::unique_ptr<Pooling2dWorkload> CreatePooling2dWorkloadTest(armnn::IWorkloadFactory& factory,
533 // Creates the layer we're testing.
534 Pooling2dDescriptor layerDesc;
535 layerDesc.m_PoolType = PoolingAlgorithm::Average;
536 layerDesc.m_PoolWidth = 3;
537 layerDesc.m_PoolHeight = 3;
538 layerDesc.m_PadLeft = 2;
539 layerDesc.m_PadRight = 2;
540 layerDesc.m_PadTop = 1;
541 layerDesc.m_PadBottom = 1;
542 layerDesc.m_StrideX = 2;
543 layerDesc.m_StrideY = 3;
544 layerDesc.m_OutputShapeRounding = OutputShapeRounding::Floor;
546 Pooling2dLayer* const layer = graph.AddLayer<Pooling2dLayer>(layerDesc, "layer");
548 // Create extra layers
549 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
550 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
553 Connect(input, layer, TensorInfo({3, 2, 5, 5}, DataType));
554 Connect(layer, output, TensorInfo({3, 2, 2, 4}, DataType));
555 CreateTensorHandles(graph, factory);
557 // Make the workload and checks it
558 auto workload = MakeAndCheckWorkload<Pooling2dWorkload>(*layer, graph, factory);
560 Pooling2dQueueDescriptor queueDescriptor = workload->GetData();
561 BOOST_TEST((queueDescriptor.m_Parameters.m_PoolType == PoolingAlgorithm::Average));
562 BOOST_TEST((queueDescriptor.m_Parameters.m_OutputShapeRounding == OutputShapeRounding::Floor));
563 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolWidth == 3);
564 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolHeight == 3);
565 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
566 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 3);
567 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 2);
568 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
569 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
570 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
572 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
573 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
575 // Return so we can do extra, backend-specific tests
579 template <typename SoftmaxWorkload, armnn::DataType DataType>
580 std::unique_ptr<SoftmaxWorkload> CreateSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory,
583 // Create the layer we're testing.
584 SoftmaxDescriptor softmaxDescriptor;
585 Layer* const layer = graph.AddLayer<SoftmaxLayer>(softmaxDescriptor, "layer");
587 // Create extra layers.
588 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
589 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
592 armnn::TensorInfo tensorInfo({4, 1}, DataType);
593 Connect(input, layer, tensorInfo);
594 Connect(layer, output, tensorInfo);
595 CreateTensorHandles(graph, factory);
597 // Make the workload and checks it.
598 auto workload = MakeAndCheckWorkload<SoftmaxWorkload>(*layer, graph, factory);
600 SoftmaxQueueDescriptor queueDescriptor = workload->GetData();
601 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
602 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
604 // Return so we can do extra, backend-specific tests.
608 template<typename SplitterWorkload, armnn::DataType DataType>
609 std::unique_ptr<SplitterWorkload>
610 CreateSplitterWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
612 // Create the layer we're testing.
613 // NOTE: need three dimensions channels, height/y, width/x because the Compute
614 // library restricts subtensors to have the same x and y dimensions as
615 // their parent tensors, and therefore the origin on the x and y dimension
616 // has to be zero for any view. So we need a third dimension to split...
617 // NOTE: arguments are: number of views, number of dimensions.
618 ViewsDescriptor layerDesc(3, 3);
619 // NOTE: arguments are: view, dimension, value.
620 layerDesc.SetViewOriginCoord(0, 0, 0);
621 layerDesc.SetViewOriginCoord(1, 0, 1);
622 layerDesc.SetViewOriginCoord(2, 0, 3);
624 Layer* const layer = graph.AddLayer<SplitterLayer>(layerDesc, "layer");
626 // Adds extra layers.
627 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
628 Layer* const output0 = graph.AddLayer<OutputLayer>(0, "output0");
629 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
630 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
633 armnn::TensorInfo tensorInfo({5, 7, 7}, DataType);
634 Connect(input, layer, tensorInfo);
636 armnn::TensorInfo output0Info({1, 7, 7}, DataType);
637 armnn::TensorInfo output1Info({2, 7, 7}, DataType);
638 armnn::TensorInfo output2Info({2, 7, 7}, DataType);
640 Connect(layer, output0, output0Info, 0, 0);
641 Connect(layer, output1, output1Info, 1, 0);
642 Connect(layer, output2, output2Info, 2, 0);
644 CreateTensorHandles(graph, factory);
646 // Makes the workload and checks it.
647 auto workload = MakeAndCheckWorkload<SplitterWorkload>(*layer, graph, factory);
649 SplitterQueueDescriptor queueDescriptor = workload->GetData();
650 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
651 BOOST_TEST(queueDescriptor.m_Outputs.size() == 3);
652 BOOST_TEST(queueDescriptor.m_ViewOrigins.size() == 3);
654 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[0] == 0);
655 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[0] == 1);
656 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[0] == 3);
657 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[1] == 0);
658 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[1] == 0);
659 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[1] == 0);
660 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[2] == 0);
661 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[2] == 0);
662 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[2] == 0);
664 // Returns so we can do extra, backend-specific tests.
668 /// This function constructs a graph with both a splitter and a merger, and returns a pair of the workloads.
669 template<typename SplitterWorkload, typename MergerWorkload, armnn::DataType DataType>
670 std::pair<std::unique_ptr<SplitterWorkload>, std::unique_ptr<MergerWorkload>>
671 CreateSplitterMergerWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
673 armnn::TensorInfo inputTensorInfo({ 1, 2, 100, 10 }, DataType);
675 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 10 }, DataType);
676 armnn::TensorInfo splitTensorInfo2({ 1, 1, 100, 10 }, DataType);
678 //Constructs the graph.
679 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
681 armnn::ViewsDescriptor splitterViews(2);
682 splitterViews.SetViewOriginCoord(0, 0, 0);
683 splitterViews.SetViewOriginCoord(0, 1, 0);
684 splitterViews.SetViewOriginCoord(0, 2, 0);
685 splitterViews.SetViewOriginCoord(0, 3, 0);
687 splitterViews.SetViewOriginCoord(1, 0, 0);
688 splitterViews.SetViewOriginCoord(1, 1, 1);
689 splitterViews.SetViewOriginCoord(1, 2, 0);
690 splitterViews.SetViewOriginCoord(1, 3, 0);
692 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
693 BOOST_TEST_CHECKPOINT("created splitter layer");
695 armnn::OriginsDescriptor mergerViews(2);
696 mergerViews.SetViewOriginCoord(0, 0, 0);
697 mergerViews.SetViewOriginCoord(0, 1, 1);
698 mergerViews.SetViewOriginCoord(0, 2, 0);
699 mergerViews.SetViewOriginCoord(0, 3, 0);
701 mergerViews.SetViewOriginCoord(1, 0, 0);
702 mergerViews.SetViewOriginCoord(1, 1, 0);
703 mergerViews.SetViewOriginCoord(1, 2, 0);
704 mergerViews.SetViewOriginCoord(1, 3, 0);
706 Layer* const merger = graph.AddLayer<MergerLayer>(mergerViews, "merger");
707 BOOST_TEST_CHECKPOINT("created merger layer");
709 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
712 Connect(input, splitter, inputTensorInfo, 0, 0);
713 BOOST_TEST_CHECKPOINT("connect input to splitter");
714 Connect(splitter, merger, splitTensorInfo1, 0, 1); // The splitter & merger are connected up.
715 BOOST_TEST_CHECKPOINT("connect splitter[0] to merger[1]");
716 Connect(splitter, merger, splitTensorInfo2, 1, 0); // So that the outputs are flipped round.
717 BOOST_TEST_CHECKPOINT("connect splitter[1] to merger[0]");
718 Connect(merger, output, inputTensorInfo, 0, 0);
719 BOOST_TEST_CHECKPOINT("connect merger to output");
721 CreateTensorHandles(graph, factory);
722 BOOST_TEST_CHECKPOINT("created tensor handles");
724 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
725 BOOST_TEST_CHECKPOINT("created splitter workload");
726 auto workloadMerger = MakeAndCheckWorkload<MergerWorkload>(*merger, graph, factory);
727 BOOST_TEST_CHECKPOINT("created merger workload");
729 return {std::move(workloadSplitter), std::move(workloadMerger)};
733 /// This function constructs a graph with a splitter with two outputs. Each of the outputs is then
734 /// connected to two different activation layers
735 template<typename SplitterWorkload, typename ActivationWorkload, armnn::DataType DataType>
736 void CreateSplitterMultipleInputsOneOutputWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph,
737 std::unique_ptr<SplitterWorkload>& wlSplitter,
738 std::unique_ptr<ActivationWorkload>& wlActiv0_0,
739 std::unique_ptr<ActivationWorkload>& wlActiv0_1,
740 std::unique_ptr<ActivationWorkload>& wlActiv1_0,
741 std::unique_ptr<ActivationWorkload>& wlActiv1_1)
743 armnn::TensorInfo inputTensorInfo ({ 1, 3, 100, 50 }, DataType);
744 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 50 }, DataType);
745 armnn::TensorInfo splitTensorInfo2({ 1, 2, 100, 50 }, DataType);
747 //Constructs the graph.
748 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
750 armnn::ViewsDescriptor splitterViews(2);
752 splitterViews.SetViewOriginCoord(0, 0, 0);
753 splitterViews.SetViewOriginCoord(0, 1, 0);
754 splitterViews.SetViewOriginCoord(0, 2, 0);
755 splitterViews.SetViewOriginCoord(0, 3, 0);
757 splitterViews.SetViewOriginCoord(1, 0, 0);
758 splitterViews.SetViewOriginCoord(1, 1, 1);
759 splitterViews.SetViewOriginCoord(1, 2, 0);
760 splitterViews.SetViewOriginCoord(1, 3, 0);
762 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
764 armnn::ActivationDescriptor activationDesc;
766 Layer* const activ0_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_0");
767 Layer* const activ0_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_1");
768 Layer* const activ1_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_0");
769 Layer* const activ1_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_1");
771 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
772 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
773 Layer* const output3 = graph.AddLayer<OutputLayer>(3, "output3");
774 Layer* const output4 = graph.AddLayer<OutputLayer>(4, "output4");
777 Connect(input, splitter, inputTensorInfo, 0, 0);
778 Connect(splitter, activ0_0, splitTensorInfo1, 0, 0);
779 Connect(splitter, activ0_1, splitTensorInfo1, 0, 0);
781 Connect(splitter, activ1_0, splitTensorInfo2, 1, 0);
782 Connect(splitter, activ1_1, splitTensorInfo2, 1, 0);
784 Connect(activ0_0, output1, splitTensorInfo1, 0, 0);
785 Connect(activ0_1, output2, splitTensorInfo1, 0, 0);
786 Connect(activ1_0, output3, splitTensorInfo2, 0, 0);
787 Connect(activ1_1, output4, splitTensorInfo2, 0, 0);
789 CreateTensorHandles(graph, factory);
791 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
792 auto workloadActiv0_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_0, graph, factory);
793 auto workloadActiv0_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_1, graph, factory);
794 auto workloadActiv1_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_0, graph, factory);
795 auto workloadActiv1_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_1, graph, factory);
797 wlSplitter = std::move(workloadSplitter);
798 wlActiv0_0 = std::move(workloadActiv0_0);
799 wlActiv0_1 = std::move(workloadActiv0_1);
800 wlActiv1_0 = std::move(workloadActiv1_0);
801 wlActiv1_1 = std::move(workloadActiv1_1);
804 template <typename ResizeBilinearWorkload, armnn::DataType DataType>
805 std::unique_ptr<ResizeBilinearWorkload> CreateResizeBilinearWorkloadTest(armnn::IWorkloadFactory& factory,
808 // Creates the layer we're testing.
809 TensorShape outputShape({ 2, 3, 2, 2 });
810 ResizeBilinearDescriptor resizeDesc;
811 resizeDesc.m_TargetWidth = outputShape[3];
812 resizeDesc.m_TargetHeight = outputShape[2];
813 Layer* const layer = graph.AddLayer<ResizeBilinearLayer>(resizeDesc, "layer");
815 // Creates extra layers.
816 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
817 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
820 armnn::TensorInfo inputTensorInfo({ 2, 3, 4, 4 }, DataType);
821 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
822 Connect(input, layer, inputTensorInfo);
823 Connect(layer, output, outputTensorInfo);
824 CreateTensorHandles(graph, factory);
826 // Makes the workload and checks it.
827 auto workload = MakeAndCheckWorkload<ResizeBilinearWorkload>(*layer, graph, factory);
829 ResizeBilinearQueueDescriptor queueDescriptor = workload->GetData();
830 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
831 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
833 // Returns so we can do extra, backend-specific tests.
837 template <typename L2NormalizationWorkload, armnn::DataType DataType>
838 std::unique_ptr<L2NormalizationWorkload> CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
841 // Creates the layer we're testing.
842 Layer* const layer = graph.AddLayer<L2NormalizationLayer>("l2norm");
844 // Creates extra layers.
845 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
846 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
849 armnn::TensorInfo inputTensorInfo({ 5, 20, 50, 67 }, DataType);
850 armnn::TensorInfo outputTensorInfo({ 5, 20, 50, 67 }, DataType);
851 Connect(input, layer, inputTensorInfo);
852 Connect(layer, output, outputTensorInfo);
853 CreateTensorHandles(graph, factory);
855 // Makes the workload and checks it.
856 auto workload = MakeAndCheckWorkload<L2NormalizationWorkload>(*layer, graph, factory);
858 L2NormalizationQueueDescriptor queueDescriptor = workload->GetData();
859 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
860 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
862 // Returns so we can do extra, backend-specific tests.
866 template <typename ReshapeWorkload, armnn::DataType DataType>
867 std::unique_ptr<ReshapeWorkload> CreateReshapeWorkloadTest(armnn::IWorkloadFactory& factory,
870 // Creates the layer we're testing.
871 TensorShape outputShape({ 1, 4 });
872 ReshapeDescriptor reshapeDesc;
873 reshapeDesc.m_TargetShape = outputShape;
874 Layer* const layer = graph.AddLayer<ReshapeLayer>(reshapeDesc, "layer");
876 // Creates extra layers.
877 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
878 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
881 armnn::TensorInfo inputTensorInfo({ 4, 1 }, DataType);
882 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
883 Connect(input, layer, inputTensorInfo);
884 Connect(layer, output, outputTensorInfo);
885 CreateTensorHandles(graph, factory);
887 // Makes the workload and checks it.
888 auto workload = MakeAndCheckWorkload<ReshapeWorkload>(*layer, graph, factory);
890 ReshapeQueueDescriptor queueDescriptor = workload->GetData();
891 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
892 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
894 // Returns so we can do extra, backend-specific tests.
898 template <typename ConvertFp16ToFp32Float32Workload>
899 std::unique_ptr<ConvertFp16ToFp32Float32Workload> CreateConvertFp16ToFp32WorkloadTest(
900 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
902 // Creates the layer we're testing.
903 ConvertFp16ToFp32Layer* const layer = graph.AddLayer<ConvertFp16ToFp32Layer>("Fp16ToFp32Converter");
905 // Creates extra layers.
906 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
907 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
910 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
911 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
912 Connect(input, layer, inputTensorInfo);
913 Connect(layer, output, outputTensorInfo);
914 CreateTensorHandles(graph, factory);
916 // Makes the workload and checks it.
917 auto workload = MakeAndCheckWorkload<ConvertFp16ToFp32Float32Workload>(*layer, graph, factory);
919 ConvertFp16ToFp32QueueDescriptor queueDescriptor = workload->GetData();
920 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
921 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
923 // Returns so we can do extra, backend-specific tests.
927 template <typename ConvertFp32ToFp16Float16Workload>
928 std::unique_ptr<ConvertFp32ToFp16Float16Workload> CreateConvertFp32ToFp16WorkloadTest(
929 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
931 // Creates the layer we're testing.
932 ConvertFp32ToFp16Layer* const layer = graph.AddLayer<ConvertFp32ToFp16Layer>("Fp32ToFp16Converter");
934 // Creates extra layers.
935 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
936 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
939 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
940 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
941 Connect(input, layer, inputTensorInfo);
942 Connect(layer, output, outputTensorInfo);
943 CreateTensorHandles(graph, factory);
945 // Makes the workload and checks it.
946 auto workload = MakeAndCheckWorkload<ConvertFp32ToFp16Float16Workload>(*layer, graph, factory);
948 ConvertFp32ToFp16QueueDescriptor queueDescriptor = workload->GetData();
949 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
950 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
952 // Returns so we can do extra, backend-specific tests.