2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
7 #include <boost/test/unit_test.hpp>
9 #include <boost/cast.hpp>
11 #include "backends/WorkloadData.hpp"
16 #include "backends/CpuTensorHandle.hpp"
18 using namespace armnn;
25 // Calls CreateWorkload for a layer, and checks the returned pointer is of the correct type.
26 template<typename Workload>
27 std::unique_ptr<Workload> MakeAndCheckWorkload(Layer& layer, Graph& graph, const IWorkloadFactory& factory)
29 std::unique_ptr<IWorkload> workload = layer.CreateWorkload(graph, factory);
30 BOOST_TEST(workload.get() == boost::polymorphic_downcast<Workload*>(workload.get()),
31 "Cannot convert to derived class");
32 std::string reasonIfUnsupported;
33 layer.SetComputeDevice(factory.GetCompute());
34 BOOST_TEST(factory.IsLayerSupported(layer, layer.GetDataType(), reasonIfUnsupported));
35 return std::unique_ptr<Workload>(static_cast<Workload*>(workload.release()));
38 // Connects two layers.
39 void Connect(Layer* from, Layer* to, const TensorInfo& tensorInfo, unsigned int fromIndex = 0, unsigned int toIndex = 0)
41 from->GetOutputSlot(fromIndex).Connect(to->GetInputSlot(toIndex));
42 from->GetOutputHandler(fromIndex).SetTensorInfo(tensorInfo);
45 // Helper function to create tensor handlers for workloads, assuming they all use the same factory.
46 void CreateTensorHandles(armnn::Graph& graph, armnn::IWorkloadFactory& factory)
48 for (auto&& layer : graph.TopologicalSort())
50 layer->CreateTensorHandles(graph, factory);
54 /////////////////////////////////////////////////////////////////////////////////////////////
55 // The following functions are called by backends/test/CreateWorkload*.cpp
56 // They build very simple graphs, and then create a workload.
57 // Some checks are performed on the workload to ensure parameters have been passed correctly.
58 // They return the created workloads so that backend-specific checks can be performed.
59 /////////////////////////////////////////////////////////////////////////////////////////////
61 template <typename ActivationWorkload, armnn::DataType DataType>
62 std::unique_ptr<ActivationWorkload> CreateActivationWorkloadTest(armnn::IWorkloadFactory& factory,
65 // Creates the layer we're testing.
66 ActivationDescriptor layerDesc;
67 layerDesc.m_Function = ActivationFunction::Abs;
69 layerDesc.m_B = -10.0f;
71 ActivationLayer* const layer = graph.AddLayer<ActivationLayer>(layerDesc, "layer");
73 // Creates extra layers.
74 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
75 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
78 armnn::TensorInfo tensorInfo({1, 1}, DataType);
80 Connect(input, layer, tensorInfo);
81 Connect(layer, output, tensorInfo);
83 CreateTensorHandles(graph, factory);
85 // Makes the workload and checks it.
86 auto workload = MakeAndCheckWorkload<ActivationWorkload>(*layer, graph, factory);
88 ActivationQueueDescriptor queueDescriptor = workload->GetData();
89 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
90 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
91 BOOST_TEST(queueDescriptor.m_Parameters.m_A == 3.5f);
92 BOOST_TEST(queueDescriptor.m_Parameters.m_B == -10.0f);
93 BOOST_TEST((queueDescriptor.m_Parameters.m_Function == ActivationFunction::Abs));
95 // Returns so we can do extra, backend-specific tests.
99 template <typename AdditionWorkload, armnn::DataType DataType>
100 std::unique_ptr<AdditionWorkload> CreateAdditionWorkloadTest(armnn::IWorkloadFactory& factory,
103 // Creates the layer we're testing.
104 Layer* const layer = graph.AddLayer<AdditionLayer>("layer");
106 // Creates extra layers.
107 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
108 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
109 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
112 armnn::TensorInfo tensorInfo({2, 3}, DataType);
113 Connect(input1, layer, tensorInfo, 0, 0);
114 Connect(input2, layer, tensorInfo, 0, 1);
115 Connect(layer, output, tensorInfo);
116 CreateTensorHandles(graph, factory);
118 // Makes the workload and checks it.
119 auto workload = MakeAndCheckWorkload<AdditionWorkload>(*layer, graph, factory);
121 AdditionQueueDescriptor queueDescriptor = workload->GetData();
122 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
123 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
125 // Returns so we can do extra, backend-specific tests.
129 template <typename BatchNormalizationFloat32Workload, armnn::DataType DataType>
130 std::unique_ptr<BatchNormalizationFloat32Workload> CreateBatchNormalizationWorkloadTest(
131 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
133 // Creates the layer we're testing.
134 BatchNormalizationDescriptor layerDesc;
135 layerDesc.m_Eps = 0.05f;
137 BatchNormalizationLayer* const layer = graph.AddLayer<BatchNormalizationLayer>(layerDesc, "layer");
139 armnn::TensorInfo weightInfo({3}, DataType);
140 layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
141 layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
142 layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
143 layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
144 layer->m_Mean->Allocate();
145 layer->m_Variance->Allocate();
146 layer->m_Beta->Allocate();
147 layer->m_Gamma->Allocate();
149 // Creates extra layers.
150 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
151 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
154 armnn::TensorInfo tensorInfo({2, 3, 1, 1}, DataType);
155 Connect(input, layer, tensorInfo);
156 Connect(layer, output, tensorInfo);
157 CreateTensorHandles(graph, factory);
159 // Makes the workload and checks it.
160 auto workload = MakeAndCheckWorkload<BatchNormalizationFloat32Workload>(*layer, graph, factory);
162 BatchNormalizationQueueDescriptor queueDescriptor = workload->GetData();
163 BOOST_TEST(queueDescriptor.m_Parameters.m_Eps == 0.05f);
164 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
165 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
166 BOOST_TEST((queueDescriptor.m_Mean->GetTensorInfo() == TensorInfo({3}, DataType)));
167 BOOST_TEST((queueDescriptor.m_Variance->GetTensorInfo() == TensorInfo({3}, DataType)));
168 BOOST_TEST((queueDescriptor.m_Gamma->GetTensorInfo() == TensorInfo({3}, DataType)));
169 BOOST_TEST((queueDescriptor.m_Beta->GetTensorInfo() == TensorInfo({3}, DataType)));
171 // Returns so we can do extra, backend-specific tests.
175 template <typename Convolution2dWorkload, armnn::DataType DataType>
176 std::unique_ptr<Convolution2dWorkload> CreateConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
179 // Creates the layer we're testing.
180 Convolution2dDescriptor layerDesc;
181 layerDesc.m_PadLeft = 3;
182 layerDesc.m_PadRight = 3;
183 layerDesc.m_PadTop = 1;
184 layerDesc.m_PadBottom = 1;
185 layerDesc.m_StrideX = 2;
186 layerDesc.m_StrideY = 4;
187 layerDesc.m_BiasEnabled = true;
189 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
191 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2, 3, 5, 3}, DataType));
192 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
194 layer->m_Weight->Allocate();
195 layer->m_Bias->Allocate();
197 // Creates extra layers.
198 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
199 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
202 Connect(input, layer, TensorInfo({2, 3, 8, 16}, DataType));
203 Connect(layer, output, TensorInfo({2, 2, 2, 10}, DataType));
204 CreateTensorHandles(graph, factory);
206 // Makes the workload and checks it.
207 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
209 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
210 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
211 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
212 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
213 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
214 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
215 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
216 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
218 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
219 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
220 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 5, 3}, DataType)));
221 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() ==
222 TensorInfo({2}, GetBiasDataType(DataType))));
224 // Returns so we can do extra, backend-specific tests.
228 template <typename LstmWorkload>
229 std::unique_ptr<LstmWorkload> CreateLstmWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
231 // This parameter setting is for withCifgWithPeepholeNoProjection
232 LstmDescriptor layerDesc;
233 layerDesc.m_ActivationFunc = 4;
234 layerDesc.m_ClippingThresCell = 0.0f;
235 layerDesc.m_ClippingThresProj = 0.0f;
236 layerDesc.m_CifgEnabled = true;
237 layerDesc.m_PeepholeEnabled = true;
238 layerDesc.m_ProjectionEnabled = false;
240 LstmLayer* const layer = graph.AddLayer<LstmLayer>(layerDesc, "layer");
241 unsigned int batchSize = 2;
242 unsigned int inputSize = 2;
243 unsigned int numUnits = 4;
244 unsigned int outputSize = 4;
246 layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
247 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
248 layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>
249 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
250 layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
251 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
252 layer->m_BasicParameters.m_RecurrentToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
253 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
254 layer->m_BasicParameters.m_RecurrentToCellWeights = std::make_unique<ScopedCpuTensorHandle>
255 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
256 layer->m_BasicParameters.m_RecurrentToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
257 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
258 layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>
259 (TensorInfo({ numUnits }, DataType::Float32));
260 layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>
261 (TensorInfo({ numUnits }, DataType::Float32));
262 layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>
263 (TensorInfo({ numUnits }, DataType::Float32));
265 layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
266 layer->m_BasicParameters.m_InputToCellWeights->Allocate();
267 layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
268 layer->m_BasicParameters.m_RecurrentToForgetWeights->Allocate();
269 layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
270 layer->m_BasicParameters.m_RecurrentToOutputWeights->Allocate();
271 layer->m_BasicParameters.m_ForgetGateBias->Allocate();
272 layer->m_BasicParameters.m_CellBias->Allocate();
273 layer->m_BasicParameters.m_OutputGateBias->Allocate();
276 if (layerDesc.m_PeepholeEnabled)
278 layer->m_PeepholeParameters.m_CellToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
279 (TensorInfo({ numUnits }, DataType::Float32));
280 layer->m_PeepholeParameters.m_CellToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
281 (TensorInfo({ numUnits }, DataType::Float32));
282 layer->m_PeepholeParameters.m_CellToForgetWeights->Allocate();
283 layer->m_PeepholeParameters.m_CellToOutputWeights->Allocate();
286 // create input and output layers
287 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
288 Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
289 Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
290 Layer* const scratchBuffer = graph.AddLayer<OutputLayer>(0, "scratchBuffer");
291 Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
292 Layer* const cellStateOut = graph.AddLayer<OutputLayer>(2, "cellStateOut");
293 Layer* const output = graph.AddLayer<OutputLayer>(3, "output");
296 armnn::TensorInfo lstmTensorInfo1({ batchSize, inputSize }, DataType::Float32);
297 armnn::TensorInfo lstmTensorInfo2({ batchSize, numUnits}, DataType::Float32);
298 armnn::TensorInfo lstmTensorInfo3({ batchSize, outputSize }, DataType::Float32);
299 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits*3 }, DataType::Float32);
300 if (layerDesc.m_CifgEnabled)
302 lstmTensorInfoScratchBuff.SetShape({ batchSize, numUnits*4 });
305 Connect(input, layer, lstmTensorInfo1, 0, 0);
306 Connect(cellStateIn, layer, lstmTensorInfo2, 0, 1);
307 Connect(outputStateIn, layer, lstmTensorInfo3, 0, 2);
308 Connect(layer, scratchBuffer, lstmTensorInfoScratchBuff, 0, 0);
309 Connect(layer, outputStateOut, lstmTensorInfo3, 1, 0);
310 Connect(layer, cellStateOut, lstmTensorInfo2, 2, 0);
311 Connect(layer, output, lstmTensorInfo3, 3, 0);
313 CreateTensorHandles(graph, factory);
315 // make the workload and check it
316 auto workload = MakeAndCheckWorkload<LstmWorkload>(*layer, graph, factory);
317 LstmQueueDescriptor queueDescriptor = workload->GetData();
318 BOOST_TEST(queueDescriptor.m_Parameters.m_ActivationFunc == 4);
319 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresCell == 0.0f);
320 BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresProj == 0.0f);
321 BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
322 BOOST_TEST(queueDescriptor.m_Outputs.size() == 4);
324 BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == TensorInfo({ numUnits, inputSize },
325 DataType::Float32)));
326 BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == TensorInfo({ numUnits },
327 DataType::Float32)));
328 BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == TensorInfo({ numUnits }, DataType::Float32)));
332 template <typename Convolution2dWorkload, armnn::DataType DataType>
333 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
336 // Creates the layer we're testing.
337 Convolution2dDescriptor layerDesc;
338 layerDesc.m_PadLeft = 1;
339 layerDesc.m_PadRight = 1;
340 layerDesc.m_PadTop = 1;
341 layerDesc.m_PadBottom = 1;
342 layerDesc.m_StrideX = 1;
343 layerDesc.m_StrideY = 1;
344 layerDesc.m_BiasEnabled = true;
346 Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
348 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
349 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
351 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({ 2, 3, 3, 3 }, DataType, inputsQScale));
352 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>
353 (TensorInfo({2}, GetBiasDataType(DataType), inputsQScale));
354 layer->m_Weight->Allocate();
355 layer->m_Bias->Allocate();
357 // Creates extra layers.
358 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
359 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
362 Connect(input, layer, TensorInfo({2, 3, 6, 6}, DataType, inputsQScale));
363 Connect(layer, output, TensorInfo({2, 2, 6, 6}, DataType, outputQScale));
364 CreateTensorHandles(graph, factory);
366 // Makes the workload and checks it.
367 auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, graph, factory);
369 Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
370 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
371 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
372 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
373 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 1);
374 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
375 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
376 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
378 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
379 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
380 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 3, 3},
381 DataType, inputsQScale)));
382 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo()
383 == TensorInfo({2}, GetBiasDataType(DataType), inputsQScale)));
385 // Returns so we can do extra, backend-specific tests.
389 template <typename DepthwiseConvolution2dFloat32Workload>
390 std::unique_ptr<DepthwiseConvolution2dFloat32Workload> CreateDepthwiseConvolution2dWorkloadTest(
391 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
393 // Creates the layer we're testing.
394 DepthwiseConvolution2dDescriptor layerDesc;
395 layerDesc.m_PadLeft = 3;
396 layerDesc.m_PadRight = 3;
397 layerDesc.m_PadTop = 1;
398 layerDesc.m_PadBottom = 1;
399 layerDesc.m_StrideX = 2;
400 layerDesc.m_StrideY = 4;
401 layerDesc.m_BiasEnabled = true;
403 DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
405 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({3, 3, 5, 3}, DataType::Float32));
406 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({9}, DataType::Float32));
407 layer->m_Weight->Allocate();
408 layer->m_Bias->Allocate();
410 // Creates extra layers.
411 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
412 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
415 Connect(input, layer, TensorInfo({2, 3, 8, 16}, armnn::DataType::Float32));
416 Connect(layer, output, TensorInfo({2, 9, 2, 10}, armnn::DataType::Float32));
417 CreateTensorHandles(graph, factory);
419 // Makes the workload and checks it.
420 auto workload = MakeAndCheckWorkload<DepthwiseConvolution2dFloat32Workload>(*layer, graph, factory);
422 DepthwiseConvolution2dQueueDescriptor queueDescriptor = workload->GetData();
423 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
424 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
425 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
426 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
427 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
428 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
429 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
431 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
432 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
433 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({3, 3, 5, 3}, DataType::Float32)));
434 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({9}, DataType::Float32)));
436 // Returns so we can do extra, backend-specific tests.
440 template <typename FullyConnectedWorkload, armnn::DataType DataType>
441 std::unique_ptr<FullyConnectedWorkload> CreateFullyConnectedWorkloadTest(armnn::IWorkloadFactory& factory,
444 // Creates the layer we're testing.
445 FullyConnectedDescriptor layerDesc;
446 layerDesc.m_BiasEnabled = true;
447 layerDesc.m_TransposeWeightMatrix = true;
449 FullyConnectedLayer* const layer = graph.AddLayer<FullyConnectedLayer>(layerDesc, "layer");
451 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
452 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
454 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7, 20}, DataType, inputsQScale, 0));
455 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7}, GetBiasDataType(DataType), inputsQScale));
456 layer->m_Weight->Allocate();
457 layer->m_Bias->Allocate();
459 // Creates extra layers.
460 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
461 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
464 Connect(input, layer, TensorInfo({3, 1, 4, 5}, DataType, inputsQScale));
465 Connect(layer, output, TensorInfo({3, 7}, DataType, outputQScale));
466 CreateTensorHandles(graph, factory);
468 // Makes the workload and checks it.
469 auto workload = MakeAndCheckWorkload<FullyConnectedWorkload>(*layer, graph, factory);
471 FullyConnectedQueueDescriptor queueDescriptor = workload->GetData();
472 BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
473 BOOST_TEST(queueDescriptor.m_Parameters.m_TransposeWeightMatrix == true);
475 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
476 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
477 BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({7, 20}, DataType, inputsQScale)));
478 BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({7}, GetBiasDataType(DataType), inputsQScale)));
480 // Returns so we can do extra, backend-specific tests.
484 template <typename MultiplicationWorkload, armnn::DataType DataType>
485 std::unique_ptr<MultiplicationWorkload> CreateMultiplicationWorkloadTest(armnn::IWorkloadFactory& factory,
488 // Creates the layer we're testing.
489 Layer* const layer = graph.AddLayer<MultiplicationLayer>("layer");
491 // Creates extra layers.
492 Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
493 Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
494 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
497 armnn::TensorInfo tensorInfo({2, 3}, DataType);
498 Connect(input1, layer, tensorInfo, 0, 0);
499 Connect(input2, layer, tensorInfo, 0, 1);
500 Connect(layer, output, tensorInfo);
501 CreateTensorHandles(graph, factory);
503 // Makes the workload and checks it.
504 auto workload = MakeAndCheckWorkload<MultiplicationWorkload>(*layer, graph, factory);
506 MultiplicationQueueDescriptor queueDescriptor = workload->GetData();
507 BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
508 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
510 // Returns so we can do extra, backend-specific tests.
514 template <typename NormalizationFloat32Workload, armnn::DataType DataType>
515 std::unique_ptr<NormalizationFloat32Workload> CreateNormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
518 // Creates the layer we're testing.
519 NormalizationDescriptor layerDesc;
520 layerDesc.m_NormChannelType = NormalizationAlgorithmChannel::Across;
521 layerDesc.m_NormMethodType = NormalizationAlgorithmMethod::LocalBrightness;
522 layerDesc.m_NormSize = 3;
523 layerDesc.m_Alpha = 0.5f;
524 layerDesc.m_Beta = -1.0f;
525 layerDesc.m_K = 0.2f;
527 NormalizationLayer* layer = graph.AddLayer<NormalizationLayer>(layerDesc, "layer");
529 // Creatse extra layers.
530 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
531 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
534 Connect(input, layer, TensorInfo({3, 5, 5, 1}, DataType));
535 Connect(layer, output, TensorInfo({3, 5, 5, 1}, DataType));
536 CreateTensorHandles(graph, factory);
538 // Makes the workload and checks it.
539 auto workload = MakeAndCheckWorkload<NormalizationFloat32Workload>(*layer, graph, factory);
541 NormalizationQueueDescriptor queueDescriptor = workload->GetData();
542 BOOST_TEST((queueDescriptor.m_Parameters.m_NormChannelType == NormalizationAlgorithmChannel::Across));
543 BOOST_TEST((queueDescriptor.m_Parameters.m_NormMethodType == NormalizationAlgorithmMethod::LocalBrightness));
544 BOOST_TEST(queueDescriptor.m_Parameters.m_NormSize == 3);
545 BOOST_TEST(queueDescriptor.m_Parameters.m_Alpha == 0.5f);
546 BOOST_TEST(queueDescriptor.m_Parameters.m_Beta == -1.0f);
547 BOOST_TEST(queueDescriptor.m_Parameters.m_K == 0.2f);
549 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
550 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
552 // Returns so we can do extra, backend-specific tests.
556 template <typename Pooling2dWorkload, armnn::DataType DataType>
557 std::unique_ptr<Pooling2dWorkload> CreatePooling2dWorkloadTest(armnn::IWorkloadFactory& factory,
560 // Creates the layer we're testing.
561 Pooling2dDescriptor layerDesc;
562 layerDesc.m_PoolType = PoolingAlgorithm::Average;
563 layerDesc.m_PoolWidth = 3;
564 layerDesc.m_PoolHeight = 3;
565 layerDesc.m_PadLeft = 2;
566 layerDesc.m_PadRight = 2;
567 layerDesc.m_PadTop = 1;
568 layerDesc.m_PadBottom = 1;
569 layerDesc.m_StrideX = 2;
570 layerDesc.m_StrideY = 3;
571 layerDesc.m_OutputShapeRounding = OutputShapeRounding::Floor;
573 Pooling2dLayer* const layer = graph.AddLayer<Pooling2dLayer>(layerDesc, "layer");
575 // Create extra layers
576 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
577 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
580 Connect(input, layer, TensorInfo({3, 2, 5, 5}, DataType));
581 Connect(layer, output, TensorInfo({3, 2, 2, 4}, DataType));
582 CreateTensorHandles(graph, factory);
584 // Make the workload and checks it
585 auto workload = MakeAndCheckWorkload<Pooling2dWorkload>(*layer, graph, factory);
587 Pooling2dQueueDescriptor queueDescriptor = workload->GetData();
588 BOOST_TEST((queueDescriptor.m_Parameters.m_PoolType == PoolingAlgorithm::Average));
589 BOOST_TEST((queueDescriptor.m_Parameters.m_OutputShapeRounding == OutputShapeRounding::Floor));
590 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolWidth == 3);
591 BOOST_TEST(queueDescriptor.m_Parameters.m_PoolHeight == 3);
592 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
593 BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 3);
594 BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 2);
595 BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
596 BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
597 BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
599 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
600 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
602 // Return so we can do extra, backend-specific tests
606 template <typename SoftmaxWorkload, armnn::DataType DataType>
607 std::unique_ptr<SoftmaxWorkload> CreateSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory,
610 // Create the layer we're testing.
611 SoftmaxDescriptor softmaxDescriptor;
612 Layer* const layer = graph.AddLayer<SoftmaxLayer>(softmaxDescriptor, "layer");
614 // Create extra layers.
615 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
616 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
619 armnn::TensorInfo tensorInfo({4, 1}, DataType);
620 Connect(input, layer, tensorInfo);
621 Connect(layer, output, tensorInfo);
622 CreateTensorHandles(graph, factory);
624 // Make the workload and checks it.
625 auto workload = MakeAndCheckWorkload<SoftmaxWorkload>(*layer, graph, factory);
627 SoftmaxQueueDescriptor queueDescriptor = workload->GetData();
628 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
629 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
631 // Return so we can do extra, backend-specific tests.
635 template<typename SplitterWorkload, armnn::DataType DataType>
636 std::unique_ptr<SplitterWorkload>
637 CreateSplitterWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
639 // Create the layer we're testing.
640 // NOTE: need three dimensions channels, height/y, width/x because the Compute
641 // library restricts subtensors to have the same x and y dimensions as
642 // their parent tensors, and therefore the origin on the x and y dimension
643 // has to be zero for any view. So we need a third dimension to split...
644 // NOTE: arguments are: number of views, number of dimensions.
645 ViewsDescriptor layerDesc(3, 3);
646 // NOTE: arguments are: view, dimension, value.
647 layerDesc.SetViewOriginCoord(0, 0, 0);
648 layerDesc.SetViewOriginCoord(1, 0, 1);
649 layerDesc.SetViewOriginCoord(2, 0, 3);
651 Layer* const layer = graph.AddLayer<SplitterLayer>(layerDesc, "layer");
653 // Adds extra layers.
654 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
655 Layer* const output0 = graph.AddLayer<OutputLayer>(0, "output0");
656 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
657 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
660 armnn::TensorInfo tensorInfo({5, 7, 7}, DataType);
661 Connect(input, layer, tensorInfo);
663 armnn::TensorInfo output0Info({1, 7, 7}, DataType);
664 armnn::TensorInfo output1Info({2, 7, 7}, DataType);
665 armnn::TensorInfo output2Info({2, 7, 7}, DataType);
667 Connect(layer, output0, output0Info, 0, 0);
668 Connect(layer, output1, output1Info, 1, 0);
669 Connect(layer, output2, output2Info, 2, 0);
671 CreateTensorHandles(graph, factory);
673 // Makes the workload and checks it.
674 auto workload = MakeAndCheckWorkload<SplitterWorkload>(*layer, graph, factory);
676 SplitterQueueDescriptor queueDescriptor = workload->GetData();
677 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
678 BOOST_TEST(queueDescriptor.m_Outputs.size() == 3);
679 BOOST_TEST(queueDescriptor.m_ViewOrigins.size() == 3);
681 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[0] == 0);
682 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[0] == 1);
683 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[0] == 3);
684 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[1] == 0);
685 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[1] == 0);
686 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[1] == 0);
687 BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[2] == 0);
688 BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[2] == 0);
689 BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[2] == 0);
691 // Returns so we can do extra, backend-specific tests.
695 /// This function constructs a graph with both a splitter and a merger, and returns a pair of the workloads.
696 template<typename SplitterWorkload, typename MergerWorkload, armnn::DataType DataType>
697 std::pair<std::unique_ptr<SplitterWorkload>, std::unique_ptr<MergerWorkload>>
698 CreateSplitterMergerWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
700 armnn::TensorInfo inputTensorInfo({ 1, 2, 100, 10 }, DataType);
702 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 10 }, DataType);
703 armnn::TensorInfo splitTensorInfo2({ 1, 1, 100, 10 }, DataType);
705 //Constructs the graph.
706 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
708 armnn::ViewsDescriptor splitterViews(2);
709 splitterViews.SetViewOriginCoord(0, 0, 0);
710 splitterViews.SetViewOriginCoord(0, 1, 0);
711 splitterViews.SetViewOriginCoord(0, 2, 0);
712 splitterViews.SetViewOriginCoord(0, 3, 0);
714 splitterViews.SetViewOriginCoord(1, 0, 0);
715 splitterViews.SetViewOriginCoord(1, 1, 1);
716 splitterViews.SetViewOriginCoord(1, 2, 0);
717 splitterViews.SetViewOriginCoord(1, 3, 0);
719 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
720 BOOST_TEST_CHECKPOINT("created splitter layer");
722 armnn::OriginsDescriptor mergerViews(2);
723 mergerViews.SetViewOriginCoord(0, 0, 0);
724 mergerViews.SetViewOriginCoord(0, 1, 1);
725 mergerViews.SetViewOriginCoord(0, 2, 0);
726 mergerViews.SetViewOriginCoord(0, 3, 0);
728 mergerViews.SetViewOriginCoord(1, 0, 0);
729 mergerViews.SetViewOriginCoord(1, 1, 0);
730 mergerViews.SetViewOriginCoord(1, 2, 0);
731 mergerViews.SetViewOriginCoord(1, 3, 0);
733 Layer* const merger = graph.AddLayer<MergerLayer>(mergerViews, "merger");
734 BOOST_TEST_CHECKPOINT("created merger layer");
736 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
739 Connect(input, splitter, inputTensorInfo, 0, 0);
740 BOOST_TEST_CHECKPOINT("connect input to splitter");
741 Connect(splitter, merger, splitTensorInfo1, 0, 1); // The splitter & merger are connected up.
742 BOOST_TEST_CHECKPOINT("connect splitter[0] to merger[1]");
743 Connect(splitter, merger, splitTensorInfo2, 1, 0); // So that the outputs are flipped round.
744 BOOST_TEST_CHECKPOINT("connect splitter[1] to merger[0]");
745 Connect(merger, output, inputTensorInfo, 0, 0);
746 BOOST_TEST_CHECKPOINT("connect merger to output");
748 CreateTensorHandles(graph, factory);
749 BOOST_TEST_CHECKPOINT("created tensor handles");
751 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
752 BOOST_TEST_CHECKPOINT("created splitter workload");
753 auto workloadMerger = MakeAndCheckWorkload<MergerWorkload>(*merger, graph, factory);
754 BOOST_TEST_CHECKPOINT("created merger workload");
756 return {std::move(workloadSplitter), std::move(workloadMerger)};
760 /// This function constructs a graph with a splitter with two outputs. Each of the outputs is then
761 /// connected to two different activation layers
762 template<typename SplitterWorkload, typename ActivationWorkload, armnn::DataType DataType>
763 void CreateSplitterMultipleInputsOneOutputWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph,
764 std::unique_ptr<SplitterWorkload>& wlSplitter,
765 std::unique_ptr<ActivationWorkload>& wlActiv0_0,
766 std::unique_ptr<ActivationWorkload>& wlActiv0_1,
767 std::unique_ptr<ActivationWorkload>& wlActiv1_0,
768 std::unique_ptr<ActivationWorkload>& wlActiv1_1)
770 armnn::TensorInfo inputTensorInfo ({ 1, 3, 100, 50 }, DataType);
771 armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 50 }, DataType);
772 armnn::TensorInfo splitTensorInfo2({ 1, 2, 100, 50 }, DataType);
774 //Constructs the graph.
775 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
777 armnn::ViewsDescriptor splitterViews(2);
779 splitterViews.SetViewOriginCoord(0, 0, 0);
780 splitterViews.SetViewOriginCoord(0, 1, 0);
781 splitterViews.SetViewOriginCoord(0, 2, 0);
782 splitterViews.SetViewOriginCoord(0, 3, 0);
784 splitterViews.SetViewOriginCoord(1, 0, 0);
785 splitterViews.SetViewOriginCoord(1, 1, 1);
786 splitterViews.SetViewOriginCoord(1, 2, 0);
787 splitterViews.SetViewOriginCoord(1, 3, 0);
789 Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
791 armnn::ActivationDescriptor activationDesc;
793 Layer* const activ0_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_0");
794 Layer* const activ0_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_1");
795 Layer* const activ1_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_0");
796 Layer* const activ1_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_1");
798 Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
799 Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
800 Layer* const output3 = graph.AddLayer<OutputLayer>(3, "output3");
801 Layer* const output4 = graph.AddLayer<OutputLayer>(4, "output4");
804 Connect(input, splitter, inputTensorInfo, 0, 0);
805 Connect(splitter, activ0_0, splitTensorInfo1, 0, 0);
806 Connect(splitter, activ0_1, splitTensorInfo1, 0, 0);
808 Connect(splitter, activ1_0, splitTensorInfo2, 1, 0);
809 Connect(splitter, activ1_1, splitTensorInfo2, 1, 0);
811 Connect(activ0_0, output1, splitTensorInfo1, 0, 0);
812 Connect(activ0_1, output2, splitTensorInfo1, 0, 0);
813 Connect(activ1_0, output3, splitTensorInfo2, 0, 0);
814 Connect(activ1_1, output4, splitTensorInfo2, 0, 0);
816 CreateTensorHandles(graph, factory);
818 auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, graph, factory);
819 auto workloadActiv0_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_0, graph, factory);
820 auto workloadActiv0_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_1, graph, factory);
821 auto workloadActiv1_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_0, graph, factory);
822 auto workloadActiv1_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_1, graph, factory);
824 wlSplitter = std::move(workloadSplitter);
825 wlActiv0_0 = std::move(workloadActiv0_0);
826 wlActiv0_1 = std::move(workloadActiv0_1);
827 wlActiv1_0 = std::move(workloadActiv1_0);
828 wlActiv1_1 = std::move(workloadActiv1_1);
831 template <typename ResizeBilinearWorkload, armnn::DataType DataType>
832 std::unique_ptr<ResizeBilinearWorkload> CreateResizeBilinearWorkloadTest(armnn::IWorkloadFactory& factory,
835 // Creates the layer we're testing.
836 TensorShape outputShape({ 2, 3, 2, 2 });
837 ResizeBilinearDescriptor resizeDesc;
838 resizeDesc.m_TargetWidth = outputShape[3];
839 resizeDesc.m_TargetHeight = outputShape[2];
840 Layer* const layer = graph.AddLayer<ResizeBilinearLayer>(resizeDesc, "layer");
842 // Creates extra layers.
843 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
844 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
847 armnn::TensorInfo inputTensorInfo({ 2, 3, 4, 4 }, DataType);
848 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
849 Connect(input, layer, inputTensorInfo);
850 Connect(layer, output, outputTensorInfo);
851 CreateTensorHandles(graph, factory);
853 // Makes the workload and checks it.
854 auto workload = MakeAndCheckWorkload<ResizeBilinearWorkload>(*layer, graph, factory);
856 ResizeBilinearQueueDescriptor queueDescriptor = workload->GetData();
857 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
858 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
860 // Returns so we can do extra, backend-specific tests.
864 template <typename L2NormalizationWorkload, armnn::DataType DataType>
865 std::unique_ptr<L2NormalizationWorkload> CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
868 // Creates the layer we're testing.
869 Layer* const layer = graph.AddLayer<L2NormalizationLayer>("l2norm");
871 // Creates extra layers.
872 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
873 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
876 armnn::TensorInfo inputTensorInfo({ 5, 20, 50, 67 }, DataType);
877 armnn::TensorInfo outputTensorInfo({ 5, 20, 50, 67 }, DataType);
878 Connect(input, layer, inputTensorInfo);
879 Connect(layer, output, outputTensorInfo);
880 CreateTensorHandles(graph, factory);
882 // Makes the workload and checks it.
883 auto workload = MakeAndCheckWorkload<L2NormalizationWorkload>(*layer, graph, factory);
885 L2NormalizationQueueDescriptor queueDescriptor = workload->GetData();
886 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
887 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
889 // Returns so we can do extra, backend-specific tests.
893 template <typename ReshapeWorkload, armnn::DataType DataType>
894 std::unique_ptr<ReshapeWorkload> CreateReshapeWorkloadTest(armnn::IWorkloadFactory& factory,
897 // Creates the layer we're testing.
898 TensorShape outputShape({ 1, 4 });
899 ReshapeDescriptor reshapeDesc;
900 reshapeDesc.m_TargetShape = outputShape;
901 Layer* const layer = graph.AddLayer<ReshapeLayer>(reshapeDesc, "layer");
903 // Creates extra layers.
904 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
905 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
908 armnn::TensorInfo inputTensorInfo({ 4, 1 }, DataType);
909 armnn::TensorInfo outputTensorInfo(outputShape, DataType);
910 Connect(input, layer, inputTensorInfo);
911 Connect(layer, output, outputTensorInfo);
912 CreateTensorHandles(graph, factory);
914 // Makes the workload and checks it.
915 auto workload = MakeAndCheckWorkload<ReshapeWorkload>(*layer, graph, factory);
917 ReshapeQueueDescriptor queueDescriptor = workload->GetData();
918 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
919 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
921 // Returns so we can do extra, backend-specific tests.
925 template <typename ConvertFp16ToFp32Float32Workload>
926 std::unique_ptr<ConvertFp16ToFp32Float32Workload> CreateConvertFp16ToFp32WorkloadTest(
927 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
929 // Creates the layer we're testing.
930 ConvertFp16ToFp32Layer* const layer = graph.AddLayer<ConvertFp16ToFp32Layer>("Fp16ToFp32Converter");
932 // Creates extra layers.
933 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
934 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
937 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
938 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
939 Connect(input, layer, inputTensorInfo);
940 Connect(layer, output, outputTensorInfo);
941 CreateTensorHandles(graph, factory);
943 // Makes the workload and checks it.
944 auto workload = MakeAndCheckWorkload<ConvertFp16ToFp32Float32Workload>(*layer, graph, factory);
946 ConvertFp16ToFp32QueueDescriptor queueDescriptor = workload->GetData();
947 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
948 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
950 // Returns so we can do extra, backend-specific tests.
954 template <typename ConvertFp32ToFp16Float16Workload>
955 std::unique_ptr<ConvertFp32ToFp16Float16Workload> CreateConvertFp32ToFp16WorkloadTest(
956 armnn::IWorkloadFactory& factory, armnn::Graph& graph)
958 // Creates the layer we're testing.
959 ConvertFp32ToFp16Layer* const layer = graph.AddLayer<ConvertFp32ToFp16Layer>("Fp32ToFp16Converter");
961 // Creates extra layers.
962 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
963 Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
966 armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
967 armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
968 Connect(input, layer, inputTensorInfo);
969 Connect(layer, output, outputTensorInfo);
970 CreateTensorHandles(graph, factory);
972 // Makes the workload and checks it.
973 auto workload = MakeAndCheckWorkload<ConvertFp32ToFp16Float16Workload>(*layer, graph, factory);
975 ConvertFp32ToFp16QueueDescriptor queueDescriptor = workload->GetData();
976 BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
977 BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
979 // Returns so we can do extra, backend-specific tests.