2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
7 #include <boost/test/unit_test.hpp>
9 #include <boost/cast.hpp>
11 #include <backends/WorkloadData.hpp>
12 #include <backends/WorkloadFactory.hpp>
13 #include <backends/CpuTensorHandle.hpp>
20 using namespace armnn;
27 // Calls CreateWorkload for a layer, and checks the returned pointer is of the correct type.
28 template<typename Workload>
29 std::unique_ptr<Workload> MakeAndCheckWorkload(Layer& layer, Graph& graph, const IWorkloadFactory& factory)
31 std::unique_ptr<IWorkload> workload = layer.CreateWorkload(graph, factory);
32 BOOST_TEST(workload.get() == boost::polymorphic_downcast<Workload*>(workload.get()),
33 "Cannot convert to derived class");
34 std::string reasonIfUnsupported;
35 layer.SetComputeDevice(factory.GetCompute());
36 BOOST_TEST(factory.IsLayerSupported(layer, layer.GetDataType(), reasonIfUnsupported));
37 return std::unique_ptr<Workload>(static_cast<Workload*>(workload.release()));
40 // Connects two layers.
41 void Connect(Layer* from, Layer* to, const TensorInfo& tensorInfo, unsigned int fromIndex = 0, unsigned int toIndex = 0)
43 from->GetOutputSlot(fromIndex).Connect(to->GetInputSlot(toIndex));
44 from->GetOutputHandler(fromIndex).SetTensorInfo(tensorInfo);
47 // Helper function to create tensor handlers for workloads, assuming they all use the same factory.
48 void CreateTensorHandles(armnn::Graph& graph, armnn::IWorkloadFactory& factory)
50 for (auto&& layer : graph.TopologicalSort())
52 layer->CreateTensorHandles(graph, factory);
56 /////////////////////////////////////////////////////////////////////////////////////////////
57 // The following functions are called by backends/test/CreateWorkload*.cpp
58 // They build very simple graphs, and then create a workload.
59 // Some checks are performed on the workload to ensure parameters have been passed correctly.
60 // They return the created workloads so that backend-specific checks can be performed.
61 /////////////////////////////////////////////////////////////////////////////////////////////
63 template <typename ActivationWorkload, armnn::DataType DataType>
64 std::unique_ptr<ActivationWorkload> CreateActivationWorkloadTest(armnn::IWorkloadFactory& factory,
67 // Creates the layer we're testing.
68 ActivationDescriptor layerDesc;
69 layerDesc.m_Function = ActivationFunction::Abs;
71 layerDesc.m_B = -10.0f;
73 ActivationLayer* const layer = graph.AddLayer<ActivationLayer>(layerDesc, "layer");
75 // Creates extra layers.
76 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
77 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
80 armnn::TensorInfo tensorInfo({1, 1}, DataType);
82 Connect(input, layer, tensorInfo);
83 Connect(layer, output, tensorInfo);
85 CreateTensorHandles(graph, factory);
87 // Makes the workload and checks it.
88 auto workload = MakeAndCheckWorkload<ActivationWorkload>(*layer, graph, factory);
90 ActivationQueueDescriptor queueDescriptor = workload->GetData();
91 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
92 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
93 BOOST_TEST(queueDescriptor.m_Parameters.m_A == 3.5f);
94 BOOST_TEST(queueDescriptor.m_Parameters.m_B == -10.0f);
95 BOOST_TEST((queueDescriptor.m_Parameters.m_Function == ActivationFunction::Abs));
97 // Returns so we can do extra, backend-specific tests.
101 template <typename WorkloadType,
102 typename DescriptorType,
104 armnn::DataType DataType>
105 std::unique_ptr<WorkloadType> CreateArithmeticWorkloadTest(armnn::IWorkloadFactory& factory,
108 // Creates the layer we're testing.
109 Layer* const layer = graph.AddLayer<LayerType>("layer");
111 // Creates extra layers.
112 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
113 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
114 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
117 armnn::TensorInfo tensorInfo({2, 3}, DataType);
118 Connect(input1, layer, tensorInfo, 0, 0);
119 Connect(input2, layer, tensorInfo, 0, 1);
120 Connect(layer, output, tensorInfo);
121 CreateTensorHandles(graph, factory);
123 // Makes the workload and checks it.
124 auto workload = MakeAndCheckWorkload<WorkloadType>(*layer, graph, factory);
126 DescriptorType queueDescriptor = workload->GetData();
127 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
128 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
130 // Returns so we can do extra, backend-specific tests.
134 template <typename BatchNormalizationFloat32Workload, armnn::DataType DataType>
135 std::unique_ptr<BatchNormalizationFloat32Workload> CreateBatchNormalizationWorkloadTest(
136 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
138 // Creates the layer we're testing.
139 BatchNormalizationDescriptor layerDesc;
140 layerDesc.m_Eps = 0.05f;
142 BatchNormalizationLayer* const layer = graph.AddLayer<BatchNormalizationLayer>(layerDesc, "layer");
144 armnn::TensorInfo weightInfo({3}, DataType);
145 layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
146 layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
147 layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
148 layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
149 layer->m_Mean->Allocate();
150 layer->m_Variance->Allocate();
151 layer->m_Beta->Allocate();
152 layer->m_Gamma->Allocate();
154 // Creates extra layers.
155 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
156 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
159 armnn::TensorInfo tensorInfo({2, 3, 1, 1}, DataType);
160 Connect(input, layer, tensorInfo);
161 Connect(layer, output, tensorInfo);
162 CreateTensorHandles(graph, factory);
164 // Makes the workload and checks it.
165 auto workload = MakeAndCheckWorkload<BatchNormalizationFloat32Workload>(*layer, graph, factory);
166 BatchNormalizationQueueDescriptor queueDescriptor = workload->GetData();
167 BOOST_TEST(queueDescriptor.m_Parameters.m_Eps == 0.05f);
168 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
169 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
170 BOOST_TEST((queueDescriptor.m_Mean->GetTensorInfo() == TensorInfo({3}, DataType)));
171 BOOST_TEST((queueDescriptor.m_Variance->GetTensorInfo() == TensorInfo({3}, DataType)));
172 BOOST_TEST((queueDescriptor.m_Gamma->GetTensorInfo() == TensorInfo({3}, DataType)));
173 BOOST_TEST((queueDescriptor.m_Beta->GetTensorInfo() == TensorInfo({3}, DataType)));
175 // Returns so we can do extra, backend-specific tests.
179 template <typename Convolution2dWorkload, armnn::DataType DataType>
180 std::unique_ptr<Convolution2dWorkload> CreateConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
182 DataLayout dataLayout = DataLayout::NCHW)
184 // Creates the layer we're testing.
185 Convolution2dDescriptor layerDesc;
186 layerDesc.m_PadLeft = 3;
187 layerDesc.m_PadRight = 3;
188 layerDesc.m_PadTop = 1;
189 layerDesc.m_PadBottom = 1;
190 layerDesc.m_StrideX = 2;
191 layerDesc.m_StrideY = 4;
192 layerDesc.m_BiasEnabled = true;
193 layerDesc.m_DataLayout = dataLayout;
195 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
197 TensorShape weightShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 5, 3} : TensorShape{2, 5, 3, 3};
198 TensorShape inputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 8, 16} : TensorShape{2, 8, 16, 3};
199 TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 2, 2, 10} : TensorShape{2, 2, 10, 2};
201 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo(weightShape, DataType));
202 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
204 layer->m_Weight->Allocate();
205 layer->m_Bias->Allocate();
207 // Creates extra layers.
208 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
209 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
212 Connect(input, layer, TensorInfo(inputShape, DataType));
213 Connect(layer, output, TensorInfo(outputShape, DataType));
214 CreateTensorHandles(graph, factory);
216 // Makes the workload and checks it.
217 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
219 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
220 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
221 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
222 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
223 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
224 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
225 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
226 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled);
227 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
229 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
230 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
231 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo(weightShape, DataType)));
232 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() ==
233 TensorInfo({2}, GetBiasDataType(DataType))));
235 // Returns so we can do extra, backend-specific tests.
239 template <typename LstmWorkload>
240 std::unique_ptr<LstmWorkload> CreateLstmWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
242 // This parameter setting is for withCifgWithPeepholeNoProjection
243 LstmDescriptor layerDesc;
244 layerDesc.m_ActivationFunc = 4;
245 layerDesc.m_ClippingThresCell = 0.0f;
246 layerDesc.m_ClippingThresProj = 0.0f;
247 layerDesc.m_CifgEnabled = true;
248 layerDesc.m_PeepholeEnabled = true;
249 layerDesc.m_ProjectionEnabled = false;
251 LstmLayer* const layer = graph.AddLayer<LstmLayer>(layerDesc, "layer");
252 unsigned int batchSize = 2;
253 unsigned int inputSize = 2;
254 unsigned int numUnits = 4;
255 unsigned int outputSize = 4;
257 layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
258 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
259 layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>
260 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
261 layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
262 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
263 layer->m_BasicParameters.m_RecurrentToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
264 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
265 layer->m_BasicParameters.m_RecurrentToCellWeights = std::make_unique<ScopedCpuTensorHandle>
266 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
267 layer->m_BasicParameters.m_RecurrentToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
268 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
269 layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>
270 (TensorInfo({ numUnits }, DataType::Float32));
271 layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>
272 (TensorInfo({ numUnits }, DataType::Float32));
273 layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>
274 (TensorInfo({ numUnits }, DataType::Float32));
276 layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
277 layer->m_BasicParameters.m_InputToCellWeights->Allocate();
278 layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
279 layer->m_BasicParameters.m_RecurrentToForgetWeights->Allocate();
280 layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
281 layer->m_BasicParameters.m_RecurrentToOutputWeights->Allocate();
282 layer->m_BasicParameters.m_ForgetGateBias->Allocate();
283 layer->m_BasicParameters.m_CellBias->Allocate();
284 layer->m_BasicParameters.m_OutputGateBias->Allocate();
287 if (layerDesc.m_PeepholeEnabled)
289 layer->m_PeepholeParameters.m_CellToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
290 (TensorInfo({ numUnits }, DataType::Float32));
291 layer->m_PeepholeParameters.m_CellToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
292 (TensorInfo({ numUnits }, DataType::Float32));
293 layer->m_PeepholeParameters.m_CellToForgetWeights->Allocate();
294 layer->m_PeepholeParameters.m_CellToOutputWeights->Allocate();
297 // create input and output layers
298 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
299 Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
300 Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
301 Layer* const scratchBuffer = graph.AddLayer<OutputLayer>(0, "scratchBuffer");
302 Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
303 Layer* const cellStateOut = graph.AddLayer<OutputLayer>(2, "cellStateOut");
304 Layer* const output = graph.AddLayer<OutputLayer>(3, "output");
307 armnn::TensorInfo lstmTensorInfo1({ batchSize, inputSize }, DataType::Float32);
308 armnn::TensorInfo lstmTensorInfo2({ batchSize, numUnits}, DataType::Float32);
309 armnn::TensorInfo lstmTensorInfo3({ batchSize, outputSize }, DataType::Float32);
310 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits*3 }, DataType::Float32);
311 if (layerDesc.m_CifgEnabled)
313 lstmTensorInfoScratchBuff.SetShape({ batchSize, numUnits*4 });
316 Connect(input, layer, lstmTensorInfo1, 0, 0);
317 Connect(cellStateIn, layer, lstmTensorInfo2, 0, 1);
318 Connect(outputStateIn, layer, lstmTensorInfo3, 0, 2);
319 Connect(layer, scratchBuffer, lstmTensorInfoScratchBuff, 0, 0);
320 Connect(layer, outputStateOut, lstmTensorInfo3, 1, 0);
321 Connect(layer, cellStateOut, lstmTensorInfo2, 2, 0);
322 Connect(layer, output, lstmTensorInfo3, 3, 0);
324 CreateTensorHandles(graph, factory);
326 // make the workload and check it
327 auto workload = MakeAndCheckWorkload<LstmWorkload>(*layer, graph, factory);
328 LstmQueueDescriptor queueDescriptor = workload->GetData();
329 BOOST_TEST(queueDescriptor.m_Parameters.m_ActivationFunc == 4);
330 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresCell == 0.0f);
331 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresProj == 0.0f);
332 BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
333 BOOST_TEST(queueDescriptor.m_Outputs.size() == 4);
335 BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == TensorInfo({ numUnits, inputSize },
336 DataType::Float32)));
337 BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == TensorInfo({ numUnits },
338 DataType::Float32)));
339 BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == TensorInfo({ numUnits }, DataType::Float32)));
343 template <typename Convolution2dWorkload, armnn::DataType DataType>
344 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
347 // Creates the layer we're testing.
348 Convolution2dDescriptor layerDesc;
349 layerDesc.m_PadLeft = 1;
350 layerDesc.m_PadRight = 1;
351 layerDesc.m_PadTop = 1;
352 layerDesc.m_PadBottom = 1;
353 layerDesc.m_StrideX = 1;
354 layerDesc.m_StrideY = 1;
355 layerDesc.m_BiasEnabled = true;
357 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
359 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
360 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
362 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({ 2, 3, 3, 3 }, DataType, inputsQScale));
363 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>
364 (TensorInfo({2}, GetBiasDataType(DataType), inputsQScale));
365 layer->m_Weight->Allocate();
366 layer->m_Bias->Allocate();
368 // Creates extra layers.
369 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
370 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
373 Connect(input, layer, TensorInfo({2, 3, 6, 6}, DataType, inputsQScale));
374 Connect(layer, output, TensorInfo({2, 2, 6, 6}, DataType, outputQScale));
375 CreateTensorHandles(graph, factory);
377 // Makes the workload and checks it.
378 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
380 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
381 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
382 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
383 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
384 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 1);
385 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
386 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
387 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
389 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
390 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
391 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 3, 3},
392 DataType, inputsQScale)));
393 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo()
394 == TensorInfo({2}, GetBiasDataType(DataType), inputsQScale)));
396 // Returns so we can do extra, backend-specific tests.
400 template <typename DepthwiseConvolution2dFloat32Workload>
401 std::unique_ptr<DepthwiseConvolution2dFloat32Workload> CreateDepthwiseConvolution2dWorkloadTest(
402 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
404 // Creates the layer we're testing.
405 DepthwiseConvolution2dDescriptor layerDesc;
406 layerDesc.m_PadLeft = 3;
407 layerDesc.m_PadRight = 3;
408 layerDesc.m_PadTop = 1;
409 layerDesc.m_PadBottom = 1;
410 layerDesc.m_StrideX = 2;
411 layerDesc.m_StrideY = 4;
412 layerDesc.m_BiasEnabled = true;
414 DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
416 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({3, 3, 5, 3}, DataType::Float32));
417 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({9}, DataType::Float32));
418 layer->m_Weight->Allocate();
419 layer->m_Bias->Allocate();
421 // Creates extra layers.
422 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
423 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
426 Connect(input, layer, TensorInfo({2, 3, 8, 16}, armnn::DataType::Float32));
427 Connect(layer, output, TensorInfo({2, 9, 2, 10}, armnn::DataType::Float32));
428 CreateTensorHandles(graph, factory);
430 // Makes the workload and checks it.
431 auto workload = MakeAndCheckWorkload<DepthwiseConvolution2dFloat32Workload>(*layer, graph, factory);
433 DepthwiseConvolution2dQueueDescriptor queueDescriptor = workload->GetData();
434 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
435 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
436 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
437 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
438 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
439 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
440 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
442 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
443 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
444 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({3, 3, 5, 3}, DataType::Float32)));
445 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({9}, DataType::Float32)));
447 // Returns so we can do extra, backend-specific tests.
451 template <typename FullyConnectedWorkload, armnn::DataType DataType>
452 std::unique_ptr<FullyConnectedWorkload> CreateFullyConnectedWorkloadTest(armnn::IWorkloadFactory& factory,
455 // Creates the layer we're testing.
456 FullyConnectedDescriptor layerDesc;
457 layerDesc.m_BiasEnabled = true;
458 layerDesc.m_TransposeWeightMatrix = true;
460 FullyConnectedLayer* const layer = graph.AddLayer<FullyConnectedLayer>(layerDesc, "layer");
462 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
463 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
465 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7, 20}, DataType, inputsQScale, 0));
466 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7}, GetBiasDataType(DataType), inputsQScale));
467 layer->m_Weight->Allocate();
468 layer->m_Bias->Allocate();
470 // Creates extra layers.
471 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
472 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
475 Connect(input, layer, TensorInfo({3, 1, 4, 5}, DataType, inputsQScale));
476 Connect(layer, output, TensorInfo({3, 7}, DataType, outputQScale));
477 CreateTensorHandles(graph, factory);
479 // Makes the workload and checks it.
480 auto workload = MakeAndCheckWorkload<FullyConnectedWorkload>(*layer, graph, factory);
482 FullyConnectedQueueDescriptor queueDescriptor = workload->GetData();
483 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
484 BOOST_TEST(queueDescriptor.m_Parameters.m_TransposeWeightMatrix == true);
486 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
487 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
488 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({7, 20}, DataType, inputsQScale)));
489 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({7}, GetBiasDataType(DataType), inputsQScale)));
491 // Returns so we can do extra, backend-specific tests.
495 template <typename NormalizationWorkload, armnn::DataType DataType>
496 std::unique_ptr<NormalizationWorkload> CreateNormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
498 DataLayout dataLayout = DataLayout::NCHW)
500 // Creates the layer we're testing.
501 NormalizationDescriptor layerDesc;
502 layerDesc.m_NormChannelType = NormalizationAlgorithmChannel::Across;
503 layerDesc.m_NormMethodType = NormalizationAlgorithmMethod::LocalBrightness;
504 layerDesc.m_NormSize = 3;
505 layerDesc.m_Alpha = 0.5f;
506 layerDesc.m_Beta = -1.0f;
507 layerDesc.m_K = 0.2f;
508 layerDesc.m_DataLayout = dataLayout;
510 NormalizationLayer* layer = graph.AddLayer<NormalizationLayer>(layerDesc, "layer");
512 // Creates extra layers.
513 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
514 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
517 Connect(input, layer, TensorInfo({3, 5, 5, 1}, DataType));
518 Connect(layer, output, TensorInfo({3, 5, 5, 1}, DataType));
519 CreateTensorHandles(graph, factory);
521 // Makes the workload and checks it.
522 auto workload = MakeAndCheckWorkload<NormalizationWorkload>(*layer, graph, factory);
524 NormalizationQueueDescriptor queueDescriptor = workload->GetData();
525 BOOST_TEST((queueDescriptor.m_Parameters.m_NormChannelType == NormalizationAlgorithmChannel::Across));
526 BOOST_TEST((queueDescriptor.m_Parameters.m_NormMethodType == NormalizationAlgorithmMethod::LocalBrightness));
527 BOOST_TEST(queueDescriptor.m_Parameters.m_NormSize == 3);
528 BOOST_TEST(queueDescriptor.m_Parameters.m_Alpha == 0.5f);
529 BOOST_TEST(queueDescriptor.m_Parameters.m_Beta == -1.0f);
530 BOOST_TEST(queueDescriptor.m_Parameters.m_K == 0.2f);
531 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
533 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
534 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
536 // Returns so we can do extra, backend-specific tests.
540 template <typename Pooling2dWorkload, armnn::DataType DataType>
541 std::unique_ptr<Pooling2dWorkload> CreatePooling2dWorkloadTest(armnn::IWorkloadFactory& factory,
543 DataLayout dataLayout = DataLayout::NCHW)
545 // Creates the layer we're testing.
546 Pooling2dDescriptor layerDesc;
547 layerDesc.m_PoolType = PoolingAlgorithm::Average;
548 layerDesc.m_PoolWidth = 3;
549 layerDesc.m_PoolHeight = 3;
550 layerDesc.m_PadLeft = 2;
551 layerDesc.m_PadRight = 2;
552 layerDesc.m_PadTop = 1;
553 layerDesc.m_PadBottom = 1;
554 layerDesc.m_StrideX = 2;
555 layerDesc.m_StrideY = 3;
556 layerDesc.m_OutputShapeRounding = OutputShapeRounding::Floor;
557 layerDesc.m_DataLayout = dataLayout;
559 Pooling2dLayer* const layer = graph.AddLayer<Pooling2dLayer>(layerDesc, "layer");
561 // Create extra layers
562 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
563 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
565 TensorShape inputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{3, 2, 5, 5} : TensorShape{3, 5, 5, 2};
566 TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{3, 2, 2, 4} : TensorShape{3, 2, 4, 2};
569 Connect(input, layer, TensorInfo(inputShape, DataType));
570 Connect(layer, output, TensorInfo(outputShape, DataType));
571 CreateTensorHandles(graph, factory);
573 // Make the workload and checks it
574 auto workload = MakeAndCheckWorkload<Pooling2dWorkload>(*layer, graph, factory);
576 Pooling2dQueueDescriptor queueDescriptor = workload->GetData();
577 BOOST_TEST((queueDescriptor.m_Parameters.m_PoolType == PoolingAlgorithm::Average));
578 BOOST_TEST((queueDescriptor.m_Parameters.m_OutputShapeRounding == OutputShapeRounding::Floor));
579 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolWidth == 3);
580 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolHeight == 3);
581 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
582 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 3);
583 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 2);
584 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
585 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
586 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
588 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
589 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
591 // Return so we can do extra, backend-specific tests
595 template <typename SoftmaxWorkload, armnn::DataType DataType>
596 std::unique_ptr<SoftmaxWorkload> CreateSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory,
599 // Create the layer we're testing.
600 SoftmaxDescriptor softmaxDescriptor;
601 Layer* const layer = graph.AddLayer<SoftmaxLayer>(softmaxDescriptor, "layer");
603 // Create extra layers.
604 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
605 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
608 armnn::TensorInfo tensorInfo({4, 1}, DataType);
609 Connect(input, layer, tensorInfo);
610 Connect(layer, output, tensorInfo);
611 CreateTensorHandles(graph, factory);
613 // Make the workload and checks it.
614 auto workload = MakeAndCheckWorkload<SoftmaxWorkload>(*layer, graph, factory);
616 SoftmaxQueueDescriptor queueDescriptor = workload->GetData();
617 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
618 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
620 // Return so we can do extra, backend-specific tests.
624 template<typename SplitterWorkload, armnn::DataType DataType>
625 std::unique_ptr<SplitterWorkload>
626 CreateSplitterWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
628 // Create the layer we're testing.
629 // NOTE: need three dimensions channels, height/y, width/x because the Compute
630 // library restricts subtensors to have the same x and y dimensions as
631 // their parent tensors, and therefore the origin on the x and y dimension
632 // has to be zero for any view. So we need a third dimension to split...
633 // NOTE: arguments are: number of views, number of dimensions.
634 ViewsDescriptor layerDesc(3, 3);
635 // NOTE: arguments are: view, dimension, value.
636 layerDesc.SetViewOriginCoord(0, 0, 0);
637 layerDesc.SetViewOriginCoord(1, 0, 1);
638 layerDesc.SetViewOriginCoord(2, 0, 3);
640 Layer* const layer = graph.AddLayer<SplitterLayer>(layerDesc, "layer");
642 // Adds extra layers.
643 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
644 Layer* const output0 = graph.AddLayer<OutputLayer>(0, "output0");
645 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
646 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
649 armnn::TensorInfo tensorInfo({5, 7, 7}, DataType);
650 Connect(input, layer, tensorInfo);
652 armnn::TensorInfo output0Info({1, 7, 7}, DataType);
653 armnn::TensorInfo output1Info({2, 7, 7}, DataType);
654 armnn::TensorInfo output2Info({2, 7, 7}, DataType);
656 Connect(layer, output0, output0Info, 0, 0);
657 Connect(layer, output1, output1Info, 1, 0);
658 Connect(layer, output2, output2Info, 2, 0);
660 CreateTensorHandles(graph, factory);
662 // Makes the workload and checks it.
663 auto workload = MakeAndCheckWorkload<SplitterWorkload>(*layer, graph, factory);
665 SplitterQueueDescriptor queueDescriptor = workload->GetData();
666 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
667 BOOST_TEST(queueDescriptor.m_Outputs.size() == 3);
668 BOOST_TEST(queueDescriptor.m_ViewOrigins.size() == 3);
670 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[0] == 0);
671 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[0] == 1);
672 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[0] == 3);
673 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[1] == 0);
674 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[1] == 0);
675 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[1] == 0);
676 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[2] == 0);
677 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[2] == 0);
678 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[2] == 0);
680 // Returns so we can do extra, backend-specific tests.
684 /// This function constructs a graph with both a splitter and a merger, and returns a pair of the workloads.
685 template<typename SplitterWorkload, typename MergerWorkload, armnn::DataType DataType>
686 std::pair<std::unique_ptr<SplitterWorkload>, std::unique_ptr<MergerWorkload>>
687 CreateSplitterMergerWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
689 armnn::TensorInfo inputTensorInfo({ 1, 2, 100, 10 }, DataType);
691 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 10 }, DataType);
692 armnn::TensorInfo splitTensorInfo2({ 1, 1, 100, 10 }, DataType);
694 //Constructs the graph.
695 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
697 armnn::ViewsDescriptor splitterViews(2);
698 splitterViews.SetViewOriginCoord(0, 0, 0);
699 splitterViews.SetViewOriginCoord(0, 1, 0);
700 splitterViews.SetViewOriginCoord(0, 2, 0);
701 splitterViews.SetViewOriginCoord(0, 3, 0);
703 splitterViews.SetViewOriginCoord(1, 0, 0);
704 splitterViews.SetViewOriginCoord(1, 1, 1);
705 splitterViews.SetViewOriginCoord(1, 2, 0);
706 splitterViews.SetViewOriginCoord(1, 3, 0);
708 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
709 BOOST_TEST_CHECKPOINT("created splitter layer");
711 armnn::OriginsDescriptor mergerViews(2);
712 mergerViews.SetViewOriginCoord(0, 0, 0);
713 mergerViews.SetViewOriginCoord(0, 1, 1);
714 mergerViews.SetViewOriginCoord(0, 2, 0);
715 mergerViews.SetViewOriginCoord(0, 3, 0);
717 mergerViews.SetViewOriginCoord(1, 0, 0);
718 mergerViews.SetViewOriginCoord(1, 1, 0);
719 mergerViews.SetViewOriginCoord(1, 2, 0);
720 mergerViews.SetViewOriginCoord(1, 3, 0);
722 Layer* const merger = graph.AddLayer<MergerLayer>(mergerViews, "merger");
723 BOOST_TEST_CHECKPOINT("created merger layer");
725 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
728 Connect(input, splitter, inputTensorInfo, 0, 0);
729 BOOST_TEST_CHECKPOINT("connect input to splitter");
730 Connect(splitter, merger, splitTensorInfo1, 0, 1); // The splitter & merger are connected up.
731 BOOST_TEST_CHECKPOINT("connect splitter[0] to merger[1]");
732 Connect(splitter, merger, splitTensorInfo2, 1, 0); // So that the outputs are flipped round.
733 BOOST_TEST_CHECKPOINT("connect splitter[1] to merger[0]");
734 Connect(merger, output, inputTensorInfo, 0, 0);
735 BOOST_TEST_CHECKPOINT("connect merger to output");
737 CreateTensorHandles(graph, factory);
738 BOOST_TEST_CHECKPOINT("created tensor handles");
740 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
741 BOOST_TEST_CHECKPOINT("created splitter workload");
742 auto workloadMerger = MakeAndCheckWorkload<MergerWorkload>(*merger, graph, factory);
743 BOOST_TEST_CHECKPOINT("created merger workload");
745 return {std::move(workloadSplitter), std::move(workloadMerger)};
749 /// This function constructs a graph with a splitter with two outputs. Each of the outputs is then
750 /// connected to two different activation layers
751 template<typename SplitterWorkload, typename ActivationWorkload, armnn::DataType DataType>
752 void CreateSplitterMultipleInputsOneOutputWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph,
753 std::unique_ptr<SplitterWorkload>& wlSplitter,
754 std::unique_ptr<ActivationWorkload>& wlActiv0_0,
755 std::unique_ptr<ActivationWorkload>& wlActiv0_1,
756 std::unique_ptr<ActivationWorkload>& wlActiv1_0,
757 std::unique_ptr<ActivationWorkload>& wlActiv1_1)
759 armnn::TensorInfo inputTensorInfo ({ 1, 3, 100, 50 }, DataType);
760 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 50 }, DataType);
761 armnn::TensorInfo splitTensorInfo2({ 1, 2, 100, 50 }, DataType);
763 //Constructs the graph.
764 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
766 armnn::ViewsDescriptor splitterViews(2);
768 splitterViews.SetViewOriginCoord(0, 0, 0);
769 splitterViews.SetViewOriginCoord(0, 1, 0);
770 splitterViews.SetViewOriginCoord(0, 2, 0);
771 splitterViews.SetViewOriginCoord(0, 3, 0);
773 splitterViews.SetViewOriginCoord(1, 0, 0);
774 splitterViews.SetViewOriginCoord(1, 1, 1);
775 splitterViews.SetViewOriginCoord(1, 2, 0);
776 splitterViews.SetViewOriginCoord(1, 3, 0);
778 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
780 armnn::ActivationDescriptor activationDesc;
782 Layer* const activ0_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_0");
783 Layer* const activ0_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_1");
784 Layer* const activ1_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_0");
785 Layer* const activ1_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_1");
787 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
788 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
789 Layer* const output3 = graph.AddLayer<OutputLayer>(3, "output3");
790 Layer* const output4 = graph.AddLayer<OutputLayer>(4, "output4");
793 Connect(input, splitter, inputTensorInfo, 0, 0);
794 Connect(splitter, activ0_0, splitTensorInfo1, 0, 0);
795 Connect(splitter, activ0_1, splitTensorInfo1, 0, 0);
797 Connect(splitter, activ1_0, splitTensorInfo2, 1, 0);
798 Connect(splitter, activ1_1, splitTensorInfo2, 1, 0);
800 Connect(activ0_0, output1, splitTensorInfo1, 0, 0);
801 Connect(activ0_1, output2, splitTensorInfo1, 0, 0);
802 Connect(activ1_0, output3, splitTensorInfo2, 0, 0);
803 Connect(activ1_1, output4, splitTensorInfo2, 0, 0);
805 CreateTensorHandles(graph, factory);
807 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
808 auto workloadActiv0_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_0, graph, factory);
809 auto workloadActiv0_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_1, graph, factory);
810 auto workloadActiv1_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_0, graph, factory);
811 auto workloadActiv1_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_1, graph, factory);
813 wlSplitter = std::move(workloadSplitter);
814 wlActiv0_0 = std::move(workloadActiv0_0);
815 wlActiv0_1 = std::move(workloadActiv0_1);
816 wlActiv1_0 = std::move(workloadActiv1_0);
817 wlActiv1_1 = std::move(workloadActiv1_1);
820 template <typename ResizeBilinearWorkload, armnn::DataType DataType>
821 std::unique_ptr<ResizeBilinearWorkload> CreateResizeBilinearWorkloadTest(armnn::IWorkloadFactory& factory,
823 DataLayout dataLayout = DataLayout::NCHW)
825 TensorShape inputShape;
826 TensorShape outputShape;
827 unsigned int heightIndex;
828 unsigned int widthIndex;
830 switch (dataLayout) {
831 case DataLayout::NHWC:
832 inputShape = { 2, 4, 4, 3 };
833 outputShape = { 2, 2, 2, 3 };
838 inputShape = { 2, 3, 4, 4 };
839 outputShape = { 2, 3, 2, 2 };
844 // Creates the layer we're testing.
845 ResizeBilinearDescriptor resizeDesc;
846 resizeDesc.m_TargetWidth = outputShape[widthIndex];
847 resizeDesc.m_TargetHeight = outputShape[heightIndex];
848 resizeDesc.m_DataLayout = dataLayout;
849 Layer* const layer = graph.AddLayer<ResizeBilinearLayer>(resizeDesc, "layer");
851 // Creates extra layers.
852 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
853 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
856 armnn::TensorInfo inputTensorInfo(inputShape, DataType);
857 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
858 Connect(input, layer, inputTensorInfo);
859 Connect(layer, output, outputTensorInfo);
860 CreateTensorHandles(graph, factory);
862 // Makes the workload and checks it.
863 auto workload = MakeAndCheckWorkload<ResizeBilinearWorkload>(*layer, graph, factory);
865 ResizeBilinearQueueDescriptor queueDescriptor = workload->GetData();
866 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
867 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
868 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
870 // Returns so we can do extra, backend-specific tests.
874 template <typename L2NormalizationWorkload, armnn::DataType DataType>
875 std::unique_ptr<L2NormalizationWorkload> CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
876 armnn::Graph& graph, DataLayout dataLayout = DataLayout::NCHW)
878 // Creates the layer we're testing.
879 L2NormalizationDescriptor layerDesc;
880 layerDesc.m_DataLayout = dataLayout;
882 Layer* const layer = graph.AddLayer<L2NormalizationLayer>(layerDesc, "l2norm");
884 // Creates extra layers.
885 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
886 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
889 armnn::TensorInfo inputTensorInfo({ 5, 20, 50, 67 }, DataType);
890 armnn::TensorInfo outputTensorInfo({ 5, 20, 50, 67 }, DataType);
891 Connect(input, layer, inputTensorInfo);
892 Connect(layer, output, outputTensorInfo);
893 CreateTensorHandles(graph, factory);
895 // Makes the workload and checks it.
896 auto workload = MakeAndCheckWorkload<L2NormalizationWorkload>(*layer, graph, factory);
898 L2NormalizationQueueDescriptor queueDescriptor = workload->GetData();
899 BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
900 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
901 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
903 // Returns so we can do extra, backend-specific tests.
907 template <typename ReshapeWorkload, armnn::DataType DataType>
908 std::unique_ptr<ReshapeWorkload> CreateReshapeWorkloadTest(armnn::IWorkloadFactory& factory,
911 // Creates the layer we're testing.
912 TensorShape outputShape({ 1, 4 });
913 ReshapeDescriptor reshapeDesc;
914 reshapeDesc.m_TargetShape = outputShape;
915 Layer* const layer = graph.AddLayer<ReshapeLayer>(reshapeDesc, "layer");
917 // Creates extra layers.
918 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
919 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
922 armnn::TensorInfo inputTensorInfo({ 4, 1 }, DataType);
923 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
924 Connect(input, layer, inputTensorInfo);
925 Connect(layer, output, outputTensorInfo);
926 CreateTensorHandles(graph, factory);
928 // Makes the workload and checks it.
929 auto workload = MakeAndCheckWorkload<ReshapeWorkload>(*layer, graph, factory);
931 ReshapeQueueDescriptor queueDescriptor = workload->GetData();
932 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
933 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
935 // Returns so we can do extra, backend-specific tests.
939 template <typename ConvertFp16ToFp32Float32Workload>
940 std::unique_ptr<ConvertFp16ToFp32Float32Workload> CreateConvertFp16ToFp32WorkloadTest(
941 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
943 // Creates the layer we're testing.
944 ConvertFp16ToFp32Layer* const layer = graph.AddLayer<ConvertFp16ToFp32Layer>("Fp16ToFp32Converter");
946 // Creates extra layers.
947 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
948 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
951 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
952 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
953 Connect(input, layer, inputTensorInfo);
954 Connect(layer, output, outputTensorInfo);
955 CreateTensorHandles(graph, factory);
957 // Makes the workload and checks it.
958 auto workload = MakeAndCheckWorkload<ConvertFp16ToFp32Float32Workload>(*layer, graph, factory);
960 ConvertFp16ToFp32QueueDescriptor queueDescriptor = workload->GetData();
961 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
962 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
964 // Returns so we can do extra, backend-specific tests.
968 template <typename ConvertFp32ToFp16Float16Workload>
969 std::unique_ptr<ConvertFp32ToFp16Float16Workload> CreateConvertFp32ToFp16WorkloadTest(
970 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
972 // Creates the layer we're testing.
973 ConvertFp32ToFp16Layer* const layer = graph.AddLayer<ConvertFp32ToFp16Layer>("Fp32ToFp16Converter");
975 // Creates extra layers.
976 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
977 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
980 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
981 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
982 Connect(input, layer, inputTensorInfo);
983 Connect(layer, output, outputTensorInfo);
984 CreateTensorHandles(graph, factory);
986 // Makes the workload and checks it.
987 auto workload = MakeAndCheckWorkload<ConvertFp32ToFp16Float16Workload>(*layer, graph, factory);
989 ConvertFp32ToFp16QueueDescriptor queueDescriptor = workload->GetData();
990 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
991 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
993 // Returns so we can do extra, backend-specific tests.