ArmNN
 20.05
CreateWorkload.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6 
7 #include "TestUtils.hpp"
8 
9 #include <Graph.hpp>
10 #include <Network.hpp>
11 #include <ResolveType.hpp>
12 
16 
20 
21 #include <boost/test/unit_test.hpp>
22 #include <boost/cast.hpp>
23 
24 #include <utility>
25 
26 using namespace armnn;
27 
28 namespace
29 {
30 
31 using namespace std;
32 
33 // Calls CreateWorkload for a layer, and checks the returned pointer is of the correct type.
34 template<typename Workload>
35 std::unique_ptr<Workload> MakeAndCheckWorkload(Layer& layer, const IWorkloadFactory& factory)
36 {
37  std::unique_ptr<IWorkload> workload = layer.CreateWorkload(factory);
38  BOOST_TEST(workload.get() == PolymorphicDowncast<Workload*>(workload.get()),
39  "Cannot convert to derived class");
40  std::string reasonIfUnsupported;
41  layer.SetBackendId(factory.GetBackendId());
42  BOOST_TEST(factory.IsLayerSupported(layer, layer.GetDataType(), reasonIfUnsupported));
43  return std::unique_ptr<Workload>(static_cast<Workload*>(workload.release()));
44 }
45 
46 // Helper function to create tensor handlers for workloads, assuming they all use the same factory.
47 void CreateTensorHandles(armnn::Graph& graph,
48  armnn::IWorkloadFactory& factory)
49 {
50  TensorHandleFactoryRegistry tmpRegistry;
51  for (auto&& layer : graph.TopologicalSort())
52  {
53  layer->CreateTensorHandles(tmpRegistry, factory);
54  }
55 }
56 
57 /////////////////////////////////////////////////////////////////////////////////////////////
58 // The following functions are called by backendsCommon/test/CreateWorkload*.cpp
59 // They build very simple graphs, and then create a workload.
60 // Some checks are performed on the workload to ensure parameters have been passed correctly.
61 // They return the created workloads so that backend-specific checks can be performed.
62 /////////////////////////////////////////////////////////////////////////////////////////////
63 
64 template <typename ActivationWorkload, armnn::DataType DataType>
65 std::unique_ptr<ActivationWorkload> CreateActivationWorkloadTest(armnn::IWorkloadFactory& factory,
66  armnn::Graph& graph)
67 {
68  // Creates the layer we're testing.
69  ActivationDescriptor layerDesc;
71  layerDesc.m_A = 3.5f;
72  layerDesc.m_B = -10.0f;
73 
74  ActivationLayer* const layer = graph.AddLayer<ActivationLayer>(layerDesc, "layer");
75 
76  // Creates extra layers.
77  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
78  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
79 
80  // Connects up.
81  armnn::TensorInfo tensorInfo({1, 1}, DataType);
82 
83  Connect(input, layer, tensorInfo);
84  Connect(layer, output, tensorInfo);
85 
86  CreateTensorHandles(graph, factory);
87 
88  // Makes the workload and checks it.
89  auto workload = MakeAndCheckWorkload<ActivationWorkload>(*layer, factory);
90 
91  ActivationQueueDescriptor queueDescriptor = workload->GetData();
92  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
93  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
94  BOOST_TEST(queueDescriptor.m_Parameters.m_A == 3.5f);
95  BOOST_TEST(queueDescriptor.m_Parameters.m_B == -10.0f);
96  BOOST_TEST((queueDescriptor.m_Parameters.m_Function == ActivationFunction::Abs));
97 
98  // Returns so we can do extra, backend-specific tests.
99  return workload;
100 }
101 
102 template <typename WorkloadType,
103  typename DescriptorType,
104  typename LayerType,
106 std::unique_ptr<WorkloadType> CreateElementwiseWorkloadTest(armnn::IWorkloadFactory & factory,
107  armnn::Graph & graph)
108 {
109  // Creates the layer we're testing.
110  Layer* const layer = graph.AddLayer<LayerType>("layer");
111 
112  // Creates extra layers.
113  Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
114  Layer* const input2 = graph.AddLayer<InputLayer>(2, "input2");
115  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
116 
117  // Connects up.
118  armnn::TensorInfo tensorInfo({2, 3}, DataType);
119  Connect(input1, layer, tensorInfo, 0, 0);
120  Connect(input2, layer, tensorInfo, 0, 1);
121  Connect(layer, output, tensorInfo);
122  CreateTensorHandles(graph, factory);
123 
124  // Makes the workload and checks it.
125  auto workload = MakeAndCheckWorkload<WorkloadType>(*layer, factory);
126 
127  DescriptorType queueDescriptor = workload->GetData();
128  BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
129  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
130 
131  // Returns so we can do extra, backend-specific tests.
132  return workload;
133 }
134 
135 template <typename WorkloadType,
136  typename DescriptorType,
138 std::unique_ptr<WorkloadType> CreateElementwiseUnaryWorkloadTest(armnn::IWorkloadFactory & factory,
139  armnn::Graph & graph,
141 {
143  Layer* const layer = graph.AddLayer<armnn::ElementwiseUnaryLayer>(desc, "layer");
144 
145  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
146  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
147 
148  armnn::TensorInfo tensorInfo({ 2, 3 }, DataType);
149  Connect(input, layer, tensorInfo, 0, 0);
150  Connect(layer, output, tensorInfo, 0, 0);
151  CreateTensorHandles(graph, factory);
152 
153  auto workload = MakeAndCheckWorkload<WorkloadType>(*layer, factory);
154  DescriptorType queueDescriptor = workload->GetData();
155 
156  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
157  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
158 
159  return workload;
160 }
161 
162 template <typename BatchNormalizationWorkloadType, armnn::DataType DataType>
163 std::unique_ptr<BatchNormalizationWorkloadType> CreateBatchNormalizationWorkloadTest(
164  armnn::IWorkloadFactory& factory, armnn::Graph& graph, DataLayout dataLayout = DataLayout::NCHW)
165 {
166  TensorShape tensorShape;
167  switch (dataLayout)
168  {
169  case DataLayout::NHWC:
170  tensorShape = { 2, 4, 4, 3 };
171  break;
172  case DataLayout::NCHW:
173  default:
174  tensorShape = { 2, 3, 4, 4 };
175  }
176 
177  // Creates the layer we're testing.
179  layerDesc.m_Eps = 0.05f;
180  layerDesc.m_DataLayout = dataLayout;
181 
182  BatchNormalizationLayer* const layer = graph.AddLayer<BatchNormalizationLayer>(layerDesc, "layer");
183 
184  armnn::TensorInfo weightInfo({3}, DataType);
185  layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
186  layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
187  layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
188  layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
189  layer->m_Mean->Allocate();
190  layer->m_Variance->Allocate();
191  layer->m_Beta->Allocate();
192  layer->m_Gamma->Allocate();
193 
194  // Creates extra layers.
195  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
196  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
197 
198  // Connects up.
199  armnn::TensorInfo tensorInfo(tensorShape, DataType);
200  Connect(input, layer, tensorInfo);
201  Connect(layer, output, tensorInfo);
202  CreateTensorHandles(graph, factory);
203 
204  // Makes the workload and checks it.
205  auto workload = MakeAndCheckWorkload<BatchNormalizationWorkloadType>(*layer, factory);
206  BatchNormalizationQueueDescriptor queueDescriptor = workload->GetData();
207  BOOST_TEST(queueDescriptor.m_Parameters.m_Eps == 0.05f);
208  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
209  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
210  BOOST_TEST((queueDescriptor.m_Mean->GetTensorInfo() == TensorInfo({3}, DataType)));
211  BOOST_TEST((queueDescriptor.m_Variance->GetTensorInfo() == TensorInfo({3}, DataType)));
212  BOOST_TEST((queueDescriptor.m_Gamma->GetTensorInfo() == TensorInfo({3}, DataType)));
213  BOOST_TEST((queueDescriptor.m_Beta->GetTensorInfo() == TensorInfo({3}, DataType)));
214  BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
215 
216  // Returns so we can do extra, backend-specific tests.
217  return workload;
218 }
219 
220 template <typename Convolution2dWorkload, armnn::DataType DataType>
221 std::unique_ptr<Convolution2dWorkload> CreateConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
222  armnn::Graph& graph,
223  DataLayout dataLayout = DataLayout::NCHW)
224 {
225  // Creates the layer we're testing.
226  Convolution2dDescriptor layerDesc;
227  layerDesc.m_PadLeft = 3;
228  layerDesc.m_PadRight = 3;
229  layerDesc.m_PadTop = 1;
230  layerDesc.m_PadBottom = 1;
231  layerDesc.m_StrideX = 2;
232  layerDesc.m_StrideY = 4;
233  layerDesc.m_BiasEnabled = true;
234  layerDesc.m_DataLayout = dataLayout;
235 
236  Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
237 
238  TensorShape weightShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 5, 3} : TensorShape{2, 5, 3, 3};
239  TensorShape inputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 8, 16} : TensorShape{2, 8, 16, 3};
240  TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 2, 2, 10} : TensorShape{2, 2, 10, 2};
241 
242  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo(weightShape, DataType));
243  layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
244 
245  layer->m_Weight->Allocate();
246  layer->m_Bias->Allocate();
247 
248  // Creates extra layers.
249  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
250  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
251 
252  // Connects up.
253  Connect(input, layer, TensorInfo(inputShape, DataType));
254  Connect(layer, output, TensorInfo(outputShape, DataType));
255  CreateTensorHandles(graph, factory);
256 
257  // Makes the workload and checks it.
258  auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, factory);
259 
260  Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
261  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
262  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 4);
263  BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 3);
264  BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 3);
265  BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
266  BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
267  BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled);
268  BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
269 
270  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
271  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
272  BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo(weightShape, DataType)));
273  BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() ==
275 
276  // Returns so we can do extra, backend-specific tests.
277  return workload;
278 }
279 
280 template <typename LstmWorkload>
281 std::unique_ptr<LstmWorkload> CreateLstmWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
282 {
283  // This parameter setting is for withCifgWithPeepholeNoProjection
284  LstmDescriptor layerDesc;
285  layerDesc.m_ActivationFunc = 4;
286  layerDesc.m_ClippingThresCell = 0.0f;
287  layerDesc.m_ClippingThresProj = 0.0f;
288  layerDesc.m_CifgEnabled = true;
289  layerDesc.m_PeepholeEnabled = true;
290  layerDesc.m_ProjectionEnabled = false;
291 
292  LstmLayer* const layer = graph.AddLayer<LstmLayer>(layerDesc, "layer");
293  unsigned int batchSize = 2;
294  unsigned int inputSize = 2;
295  unsigned int numUnits = 4;
296  unsigned int outputSize = 4;
297 
298  layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
299  (TensorInfo({ numUnits, inputSize }, DataType::Float32));
300  layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>
301  (TensorInfo({ numUnits, inputSize }, DataType::Float32));
302  layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
303  (TensorInfo({ numUnits, inputSize }, DataType::Float32));
304  layer->m_BasicParameters.m_RecurrentToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
305  (TensorInfo({ numUnits, outputSize }, DataType::Float32));
306  layer->m_BasicParameters.m_RecurrentToCellWeights = std::make_unique<ScopedCpuTensorHandle>
307  (TensorInfo({ numUnits, outputSize }, DataType::Float32));
308  layer->m_BasicParameters.m_RecurrentToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
309  (TensorInfo({ numUnits, outputSize }, DataType::Float32));
310  layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>
311  (TensorInfo({ numUnits }, DataType::Float32));
312  layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>
313  (TensorInfo({ numUnits }, DataType::Float32));
314  layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>
315  (TensorInfo({ numUnits }, DataType::Float32));
316 
317  layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
318  layer->m_BasicParameters.m_InputToCellWeights->Allocate();
319  layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
321  layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
323  layer->m_BasicParameters.m_ForgetGateBias->Allocate();
324  layer->m_BasicParameters.m_CellBias->Allocate();
325  layer->m_BasicParameters.m_OutputGateBias->Allocate();
326 
327 
328  if (layerDesc.m_PeepholeEnabled)
329  {
330  layer->m_PeepholeParameters.m_CellToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
331  (TensorInfo({ numUnits }, DataType::Float32));
332  layer->m_PeepholeParameters.m_CellToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
333  (TensorInfo({ numUnits }, DataType::Float32));
334  layer->m_PeepholeParameters.m_CellToForgetWeights->Allocate();
335  layer->m_PeepholeParameters.m_CellToOutputWeights->Allocate();
336  }
337 
338  // create input and output layers
339  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
340  Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
341  Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
342  Layer* const scratchBuffer = graph.AddLayer<OutputLayer>(0, "scratchBuffer");
343  Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
344  Layer* const cellStateOut = graph.AddLayer<OutputLayer>(2, "cellStateOut");
345  Layer* const output = graph.AddLayer<OutputLayer>(3, "output");
346 
347  // connect up
348  armnn::TensorInfo lstmTensorInfo1({ batchSize, inputSize }, DataType::Float32);
349  armnn::TensorInfo lstmTensorInfo2({ batchSize, numUnits}, DataType::Float32);
350  armnn::TensorInfo lstmTensorInfo3({ batchSize, outputSize }, DataType::Float32);
351  armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits * (layerDesc.m_CifgEnabled ? 3 : 4) },
353  Connect(input, layer, lstmTensorInfo1, 0, 0);
354  Connect(cellStateIn, layer, lstmTensorInfo2, 0, 1);
355  Connect(outputStateIn, layer, lstmTensorInfo3, 0, 2);
356  Connect(layer, scratchBuffer, lstmTensorInfoScratchBuff, 0, 0);
357  Connect(layer, outputStateOut, lstmTensorInfo3, 1, 0);
358  Connect(layer, cellStateOut, lstmTensorInfo2, 2, 0);
359  Connect(layer, output, lstmTensorInfo3, 3, 0);
360 
361  CreateTensorHandles(graph, factory);
362 
363  // make the workload and check it
364  auto workload = MakeAndCheckWorkload<LstmWorkload>(*layer, factory);
365  LstmQueueDescriptor queueDescriptor = workload->GetData();
366  BOOST_TEST(queueDescriptor.m_Parameters.m_ActivationFunc == 4);
367  BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresCell == 0.0f);
368  BOOST_TEST(queueDescriptor.m_Parameters.m_ClippingThresProj == 0.0f);
369  BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
370  BOOST_TEST(queueDescriptor.m_Outputs.size() == 4);
371 
372  BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == TensorInfo({ numUnits, inputSize },
374  BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == TensorInfo({ numUnits },
376  BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == TensorInfo({ numUnits }, DataType::Float32)));
377  return workload;
378 }
379 
380 template <typename QuantizedLstmWorkload>
381 std::unique_ptr<QuantizedLstmWorkload> CreateQuantizedLstmWorkloadTest(armnn::IWorkloadFactory& factory,
382  armnn::Graph& graph)
383 {
384  auto layer = graph.AddLayer<QuantizedLstmLayer>("quantizedLstmlayer");
385  unsigned int numBatches = 2;
386  unsigned int inputSize = 2;
387  unsigned int outputSize = 4;
388 
389  // Scale/Offset for input/output, cellState In/Out, weights, bias
390  float inputOutputScale = 0.0078125f;
391  int32_t inputOutputOffset = 128;
392 
393  float cellStateScale = 0.00048828125f;
394  int32_t cellStateOffset = 0;
395 
396  float weightsScale = 0.00408021f;
397  int32_t weightsOffset = 100;
398 
399  float biasScale = 3.1876640625e-05f;
400  int32_t biasOffset = 0;
401 
402  // Weights and bias tensor and quantization info
403  armnn::TensorInfo inputWeightsInfo({outputSize, inputSize},
405  weightsScale,
406  weightsOffset);
407 
408  armnn::TensorInfo recurrentWeightsInfo({outputSize, outputSize},
410  weightsScale,
411  weightsOffset);
412 
413  armnn::TensorInfo biasInfo({outputSize},
415  biasScale,
416  biasOffset);
417 
418  // Weights and bias
419  layer->m_QuantizedLstmParameters.m_InputToInputWeights =
420  std::make_unique<ScopedCpuTensorHandle>(inputWeightsInfo);
421  layer->m_QuantizedLstmParameters.m_InputToForgetWeights =
422  std::make_unique<ScopedCpuTensorHandle>(inputWeightsInfo);
423  layer->m_QuantizedLstmParameters.m_InputToCellWeights =
424  std::make_unique<ScopedCpuTensorHandle>(inputWeightsInfo);
425  layer->m_QuantizedLstmParameters.m_InputToOutputWeights =
426  std::make_unique<ScopedCpuTensorHandle>(inputWeightsInfo);
427 
428  layer->m_QuantizedLstmParameters.m_RecurrentToInputWeights =
429  std::make_unique<ScopedCpuTensorHandle>(recurrentWeightsInfo);
430  layer->m_QuantizedLstmParameters.m_RecurrentToForgetWeights =
431  std::make_unique<ScopedCpuTensorHandle>(recurrentWeightsInfo);
432  layer->m_QuantizedLstmParameters.m_RecurrentToCellWeights =
433  std::make_unique<ScopedCpuTensorHandle>(recurrentWeightsInfo);
434  layer->m_QuantizedLstmParameters.m_RecurrentToOutputWeights =
435  std::make_unique<ScopedCpuTensorHandle>(recurrentWeightsInfo);
436 
437  layer->m_QuantizedLstmParameters.m_InputGateBias = std::make_unique<ScopedCpuTensorHandle>(biasInfo);
438  layer->m_QuantizedLstmParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>(biasInfo);
439  layer->m_QuantizedLstmParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>(biasInfo);
440  layer->m_QuantizedLstmParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>(biasInfo);
441 
442  // Allocate weights and bias
443  layer->m_QuantizedLstmParameters.m_InputToInputWeights->Allocate();
444  layer->m_QuantizedLstmParameters.m_InputToForgetWeights->Allocate();
445  layer->m_QuantizedLstmParameters.m_InputToCellWeights->Allocate();
446  layer->m_QuantizedLstmParameters.m_InputToOutputWeights->Allocate();
447 
448  layer->m_QuantizedLstmParameters.m_RecurrentToInputWeights->Allocate();
449  layer->m_QuantizedLstmParameters.m_RecurrentToForgetWeights->Allocate();
450  layer->m_QuantizedLstmParameters.m_RecurrentToCellWeights->Allocate();
451  layer->m_QuantizedLstmParameters.m_RecurrentToOutputWeights->Allocate();
452 
453  layer->m_QuantizedLstmParameters.m_InputGateBias->Allocate();
454  layer->m_QuantizedLstmParameters.m_ForgetGateBias->Allocate();
455  layer->m_QuantizedLstmParameters.m_CellBias->Allocate();
456  layer->m_QuantizedLstmParameters.m_OutputGateBias->Allocate();
457 
458  // Create input and output layers
459  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
460  Layer* const cellStateIn = graph.AddLayer<InputLayer>(1, "cellStateIn");
461  Layer* const outputStateIn = graph.AddLayer<InputLayer>(2, "outputStateIn");
462 
463  Layer* const cellStateOut = graph.AddLayer<OutputLayer>(0, "cellStateOut");
464  Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
465 
466  // Input/output tensor info and quantization info
467  armnn::TensorInfo inputInfo({numBatches , inputSize},
469  inputOutputScale,
470  inputOutputOffset);
471 
472  armnn::TensorInfo cellStateInfo({numBatches , outputSize},
474  cellStateScale,
475  cellStateOffset);
476 
477  armnn::TensorInfo outputStateInfo({numBatches , outputSize},
479  inputOutputScale,
480  inputOutputOffset);
481 
482  // Connect input/output slots
483  Connect(input, layer, inputInfo, 0, 0);
484  Connect(cellStateIn, layer, cellStateInfo, 0, 1);
485  Connect(outputStateIn, layer, outputStateInfo, 0, 2);
486 
487  Connect(layer, cellStateOut, cellStateInfo, 0, 0);
488  Connect(layer, outputStateOut, outputStateInfo, 1, 0);
489 
490  CreateTensorHandles(graph, factory);
491 
492  // Create workload and check layer support
493  auto workload = MakeAndCheckWorkload<QuantizedLstmWorkload>(*layer, factory);
494  QuantizedLstmQueueDescriptor queueDescriptor = workload->GetData();
495 
496  // Validate input/output sizes
497  BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
498  BOOST_TEST(queueDescriptor.m_Outputs.size() == 2);
499 
500  // Validate weight tensor info
501  BOOST_TEST((queueDescriptor.m_InputToInputWeights->GetTensorInfo() == inputWeightsInfo));
502  BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == inputWeightsInfo));
503  BOOST_TEST((queueDescriptor.m_InputToCellWeights->GetTensorInfo() == inputWeightsInfo));
504  BOOST_TEST((queueDescriptor.m_InputToOutputWeights->GetTensorInfo() == inputWeightsInfo));
505 
506  BOOST_TEST((queueDescriptor.m_RecurrentToInputWeights->GetTensorInfo() == recurrentWeightsInfo));
507  BOOST_TEST((queueDescriptor.m_RecurrentToForgetWeights->GetTensorInfo() == recurrentWeightsInfo));
508  BOOST_TEST((queueDescriptor.m_RecurrentToCellWeights->GetTensorInfo() == recurrentWeightsInfo));
509  BOOST_TEST((queueDescriptor.m_RecurrentToOutputWeights->GetTensorInfo() == recurrentWeightsInfo));
510 
511  BOOST_TEST((queueDescriptor.m_InputGateBias->GetTensorInfo() == biasInfo));
512  BOOST_TEST((queueDescriptor.m_ForgetGateBias->GetTensorInfo() == biasInfo));
513  BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == biasInfo));
514  BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == biasInfo));
515 
516  return workload;
517 }
518 
519 template <typename QLstmWorkload>
520 std::unique_ptr<QLstmWorkload> CreateQLstmWorkloadTest(armnn::IWorkloadFactory& factory,
521  armnn::Graph& graph)
522 {
523  QLstmDescriptor layerDesc;
524  layerDesc.m_CifgEnabled = true;
525  layerDesc.m_PeepholeEnabled = false;
526  layerDesc.m_ProjectionEnabled = false;
527  layerDesc.m_LayerNormEnabled = true;
528 
529  layerDesc.m_CellClip = 0.0f;
530  layerDesc.m_ProjectionClip = 0.0f;
531 
532  layerDesc.m_HiddenStateZeroPoint = 0;
533  layerDesc.m_HiddenStateScale = 0.007f;
534 
535  layerDesc.m_InputIntermediateScale = 0.007059f;
536  layerDesc.m_ForgetIntermediateScale = 0.007812f;
537  layerDesc.m_CellIntermediateScale = 0.007059f;
538  layerDesc.m_OutputIntermediateScale = 0.007812f;
539 
540  QLstmLayer* const layer = graph.AddLayer<QLstmLayer>(layerDesc, "qLstm");
541 
542  unsigned int numBatches = 2;
543  unsigned int inputSize = 4;
544  unsigned int numUnits = 4;
545  unsigned int outputSize = 4;
546 
547  // Scale/Offset quantization info
548  float inputScale = 0.0078125f;
549  int32_t inputOffset = 0;
550 
551  // if (!projectionEnabled) outputScale == hiddenStateScale
552  float outputScale = layerDesc.m_HiddenStateScale;
553  int32_t outputOffset = layerDesc.m_HiddenStateZeroPoint;
554 
555  float cellStateScale = 3.05176e-05f;
556  int32_t cellStateOffset = 0;
557 
558  float weightsScale = 0.00784314f;
559  int32_t weightsOffset = 0;
560 
561  float layerNormScale = 3.05182e-05f;
562  int32_t layerNormOffset = 0;
563 
564  float biasScale = layerNormScale / 1024;
565  int32_t biasOffset = 0;
566 
567  // Weights and bias tensor and quantization info
568  armnn::TensorInfo inputWeightsInfo({outputSize, inputSize},
570  weightsScale,
571  weightsOffset);
572 
573  armnn::TensorInfo recurrentWeightsInfo({outputSize, outputSize},
575  weightsScale,
576  weightsOffset);
577 
578  armnn::TensorInfo biasInfo({outputSize}, armnn::DataType::Signed32, biasScale, biasOffset);
579 
580  armnn::TensorInfo layerNormWeightsInfo({numUnits}, armnn::DataType::QSymmS16, layerNormScale, layerNormOffset);
581 
582  // Create and allocate tensors
583  layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>(inputWeightsInfo);
584  layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>(inputWeightsInfo);
585  layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>(inputWeightsInfo);
586 
588  std::make_unique<ScopedCpuTensorHandle>(recurrentWeightsInfo);
590  std::make_unique<ScopedCpuTensorHandle>(recurrentWeightsInfo);
592  std::make_unique<ScopedCpuTensorHandle>(recurrentWeightsInfo);
593 
594  layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>(biasInfo);
595  layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>(biasInfo);
596  layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>(biasInfo);
597 
599  std::make_unique<ScopedCpuTensorHandle>(layerNormWeightsInfo);
601  std::make_unique<ScopedCpuTensorHandle>(layerNormWeightsInfo);
603  std::make_unique<ScopedCpuTensorHandle>(layerNormWeightsInfo);
604 
605  layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
606  layer->m_BasicParameters.m_InputToCellWeights->Allocate();
607  layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
608 
610  layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
612 
613  layer->m_BasicParameters.m_ForgetGateBias->Allocate();
614  layer->m_BasicParameters.m_CellBias->Allocate();
615  layer->m_BasicParameters.m_OutputGateBias->Allocate();
616 
620 
621  // Input and output layers
622  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
623  Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
624  Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
625 
626  Layer* const outputStateOut = graph.AddLayer<OutputLayer>(0, "outputStateOut");
627  Layer* const cellStateOut = graph.AddLayer<OutputLayer>(1, "cellStateOut");
628  Layer* const output = graph.AddLayer<OutputLayer>(2, "output");
629 
630  // Input/Output tensor info
631  armnn::TensorInfo inputInfo({numBatches , inputSize},
633  inputScale,
634  inputOffset);
635 
636  armnn::TensorInfo cellStateInfo({numBatches , numUnits},
638  cellStateScale,
639  cellStateOffset);
640 
641  armnn::TensorInfo outputStateInfo({numBatches , outputSize},
643  outputScale,
644  outputOffset);
645 
646  // Connect layers to slots
647  Connect(input, layer, inputInfo, 0, 0);
648  Connect(outputStateIn, layer, outputStateInfo, 0, 1);
649  Connect(cellStateIn, layer, cellStateInfo, 0, 2);
650 
651  Connect(layer, outputStateOut, outputStateInfo, 0, 0);
652  Connect(layer, cellStateOut, cellStateInfo, 1, 0);
653  Connect(layer, output, outputStateInfo, 2, 0);
654 
655  CreateTensorHandles(graph, factory);
656 
657  // Create and check workload
658  auto workload = MakeAndCheckWorkload<QLstmWorkload>(*layer, factory);
659  QLstmQueueDescriptor queueDescriptor = workload->GetData();
660  BOOST_TEST(queueDescriptor.m_Parameters.m_CellClip == 0.0f);
661  BOOST_TEST(queueDescriptor.m_Parameters.m_ProjectionClip == 0.0f);
662  BOOST_TEST(queueDescriptor.m_Inputs.size() == 3);
663  BOOST_TEST(queueDescriptor.m_Outputs.size() == 3);
664 
665  BOOST_TEST((queueDescriptor.m_InputToForgetWeights->GetTensorInfo() == inputWeightsInfo));
666  BOOST_TEST((queueDescriptor.m_InputToCellWeights->GetTensorInfo() == inputWeightsInfo));
667  BOOST_TEST((queueDescriptor.m_InputToOutputWeights->GetTensorInfo() == inputWeightsInfo));
668 
669  BOOST_TEST((queueDescriptor.m_RecurrentToForgetWeights->GetTensorInfo() == recurrentWeightsInfo));
670  BOOST_TEST((queueDescriptor.m_RecurrentToCellWeights->GetTensorInfo() == recurrentWeightsInfo));
671  BOOST_TEST((queueDescriptor.m_RecurrentToOutputWeights->GetTensorInfo() == recurrentWeightsInfo));
672 
673  BOOST_TEST((queueDescriptor.m_ForgetGateBias->GetTensorInfo() == biasInfo));
674  BOOST_TEST((queueDescriptor.m_CellBias->GetTensorInfo() == biasInfo));
675  BOOST_TEST((queueDescriptor.m_OutputGateBias->GetTensorInfo() == biasInfo));
676 
677  return workload;
678 }
679 
680 template <typename Convolution2dWorkload, armnn::DataType DataType>
681 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
682  armnn::Graph& graph)
683 {
684  // Creates the layer we're testing.
685  Convolution2dDescriptor layerDesc;
686  layerDesc.m_PadLeft = 1;
687  layerDesc.m_PadRight = 1;
688  layerDesc.m_PadTop = 1;
689  layerDesc.m_PadBottom = 1;
690  layerDesc.m_StrideX = 1;
691  layerDesc.m_StrideY = 1;
692  layerDesc.m_BiasEnabled = true;
693 
694  Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
695 
696  float inputsQScale = DataType == armnn::DataType::QAsymmU8 ? 1.0f : 0.0;
697  float outputQScale = DataType == armnn::DataType::QAsymmU8 ? 2.0f : 0.0;
698 
699  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({ 2, 3, 3, 3 }, DataType, inputsQScale));
700  layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>
701  (TensorInfo({2}, GetBiasDataType(DataType), inputsQScale));
702  layer->m_Weight->Allocate();
703  layer->m_Bias->Allocate();
704 
705  // Creates extra layers.
706  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
707  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
708 
709  // Connects up.
710  Connect(input, layer, TensorInfo({2, 3, 6, 6}, DataType, inputsQScale));
711  Connect(layer, output, TensorInfo({2, 2, 6, 6}, DataType, outputQScale));
712  CreateTensorHandles(graph, factory);
713 
714  // Makes the workload and checks it.
715  auto workload = MakeAndCheckWorkload<Convolution2dWorkload>(*layer, factory);
716 
717  Convolution2dQueueDescriptor queueDescriptor = workload->GetData();
718  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
719  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
720  BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
721  BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 1);
722  BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
723  BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
724  BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
725 
726  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
727  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
728  BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 3, 3},
729  DataType, inputsQScale)));
730  BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo()
731  == TensorInfo({2}, GetBiasDataType(DataType), inputsQScale)));
732 
733  // Returns so we can do extra, backend-specific tests.
734  return workload;
735 }
736 
737 template <typename DepthwiseConvolution2dFloat32Workload, armnn::DataType DataType>
738 std::unique_ptr<DepthwiseConvolution2dFloat32Workload> CreateDepthwiseConvolution2dWorkloadTest(
739  armnn::IWorkloadFactory& factory, armnn::Graph& graph, DataLayout dataLayout = DataLayout::NCHW)
740 {
741  // Creates the layer we're testing.
743  layerDesc.m_PadLeft = 1;
744  layerDesc.m_PadRight = 2;
745  layerDesc.m_PadTop = 1;
746  layerDesc.m_PadBottom = 2;
747  layerDesc.m_StrideX = 1;
748  layerDesc.m_StrideY = 1;
749  layerDesc.m_BiasEnabled = false;
750  layerDesc.m_DataLayout = dataLayout;
751 
752  DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
753 
754  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({1, 2, 4, 4}, DataType)); // [ M, I, H, W ]
755  layer->m_Weight->Allocate();
756 
757  // Creates extra layers.
758  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
759  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
760 
761  TensorShape inputShape = (dataLayout == DataLayout::NCHW) ?
762  TensorShape{ 2, 2, 5, 5 } : TensorShape{ 2, 5, 5, 2 };
763  TensorShape outputShape = (dataLayout == DataLayout::NCHW) ?
764  TensorShape{ 2, 2, 5, 5 } : TensorShape{ 2, 5, 5, 2 };
765 
766  // Connects up.
767  Connect(input, layer, TensorInfo(inputShape, DataType));
768  Connect(layer, output, TensorInfo(outputShape, DataType));
769  CreateTensorHandles(graph, factory);
770 
771  // Makes the workload and checks it.
772  auto workload = MakeAndCheckWorkload<DepthwiseConvolution2dFloat32Workload>(*layer, factory);
773 
774  DepthwiseConvolution2dQueueDescriptor queueDescriptor = workload->GetData();
775  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 1);
776  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 1);
777  BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 1);
778  BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
779  BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
780  BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 2);
781  BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == false);
782  BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
783 
784  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
785  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
786  BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({1, 2, 4, 4}, DataType)));
787 
788  // Returns so we can do extra, backend-specific tests.
789  return workload;
790 }
791 
792 template <typename FullyConnectedWorkload, armnn::DataType DataType>
793 std::unique_ptr<FullyConnectedWorkload> CreateFullyConnectedWorkloadTest(armnn::IWorkloadFactory& factory,
794  armnn::Graph& graph)
795 {
796  // Creates the layer we're testing.
797  FullyConnectedDescriptor layerDesc;
798  layerDesc.m_BiasEnabled = true;
799  layerDesc.m_TransposeWeightMatrix = true;
800 
801  FullyConnectedLayer* const layer = graph.AddLayer<FullyConnectedLayer>(layerDesc, "layer");
802 
803  float inputsQScale = DataType == armnn::DataType::QAsymmU8 ? 1.0f : 0.0;
804  float outputQScale = DataType == armnn::DataType::QAsymmU8 ? 2.0f : 0.0;
805 
806  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7, 20}, DataType, inputsQScale, 0));
807  layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(TensorInfo({7}, GetBiasDataType(DataType), inputsQScale));
808  layer->m_Weight->Allocate();
809  layer->m_Bias->Allocate();
810 
811  // Creates extra layers.
812  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
813  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
814 
815  // Connects up.
816  Connect(input, layer, TensorInfo({3, 1, 4, 5}, DataType, inputsQScale));
817  Connect(layer, output, TensorInfo({3, 7}, DataType, outputQScale));
818  CreateTensorHandles(graph, factory);
819 
820  // Makes the workload and checks it.
821  auto workload = MakeAndCheckWorkload<FullyConnectedWorkload>(*layer, factory);
822 
823  FullyConnectedQueueDescriptor queueDescriptor = workload->GetData();
824  BOOST_TEST(queueDescriptor.m_Parameters.m_BiasEnabled == true);
825  BOOST_TEST(queueDescriptor.m_Parameters.m_TransposeWeightMatrix == true);
826 
827  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
828  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
829  BOOST_TEST((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({7, 20}, DataType, inputsQScale)));
830  BOOST_TEST((queueDescriptor.m_Bias->GetTensorInfo() == TensorInfo({7}, GetBiasDataType(DataType), inputsQScale)));
831 
832  // Returns so we can do extra, backend-specific tests.
833  return workload;
834 }
835 
836 template <typename NormalizationWorkload, armnn::DataType DataType>
837 std::unique_ptr<NormalizationWorkload> CreateNormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
838  armnn::Graph& graph,
839  DataLayout dataLayout = DataLayout::NCHW)
840 {
841  // Creates the layer we're testing.
842  NormalizationDescriptor layerDesc;
845  layerDesc.m_NormSize = 3;
846  layerDesc.m_Alpha = 0.5f;
847  layerDesc.m_Beta = -1.0f;
848  layerDesc.m_K = 0.2f;
849  layerDesc.m_DataLayout = dataLayout;
850 
851  NormalizationLayer* layer = graph.AddLayer<NormalizationLayer>(layerDesc, "layer");
852 
853  // Creates extra layers.
854  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
855  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
856 
857  TensorShape inputShape = (dataLayout == DataLayout::NCHW) ?
858  TensorShape{ 3, 5, 5, 1 } : TensorShape{ 3, 1, 5, 5 };
859  TensorShape outputShape = (dataLayout == DataLayout::NCHW) ?
860  TensorShape{ 3, 5, 5, 1 } : TensorShape{ 3, 1, 5, 5 };
861 
862  // Connects up.
863  armnn::TensorInfo inputTensorInfo(inputShape, DataType);
864  armnn::TensorInfo outputTensorInfo(outputShape, DataType);
865  Connect(input, layer, inputTensorInfo);
866  Connect(layer, output, outputTensorInfo);
867  CreateTensorHandles(graph, factory);
868 
869  // Makes the workload and checks it.
870  auto workload = MakeAndCheckWorkload<NormalizationWorkload>(*layer, factory);
871 
872  NormalizationQueueDescriptor queueDescriptor = workload->GetData();
873  BOOST_TEST((queueDescriptor.m_Parameters.m_NormChannelType == NormalizationAlgorithmChannel::Across));
874  BOOST_TEST((queueDescriptor.m_Parameters.m_NormMethodType == NormalizationAlgorithmMethod::LocalBrightness));
875  BOOST_TEST(queueDescriptor.m_Parameters.m_NormSize == 3);
876  BOOST_TEST(queueDescriptor.m_Parameters.m_Alpha == 0.5f);
877  BOOST_TEST(queueDescriptor.m_Parameters.m_Beta == -1.0f);
878  BOOST_TEST(queueDescriptor.m_Parameters.m_K == 0.2f);
879  BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
880 
881  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
882  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
883 
884  // Returns so we can do extra, backend-specific tests.
885  return workload;
886 }
887 
888 template <typename Pooling2dWorkload, armnn::DataType DataType>
889 std::unique_ptr<Pooling2dWorkload> CreatePooling2dWorkloadTest(armnn::IWorkloadFactory& factory,
890  armnn::Graph& graph,
891  DataLayout dataLayout = DataLayout::NCHW)
892 {
893  // Creates the layer we're testing.
894  Pooling2dDescriptor layerDesc;
896  layerDesc.m_PoolWidth = 3;
897  layerDesc.m_PoolHeight = 3;
898  layerDesc.m_PadLeft = 2;
899  layerDesc.m_PadRight = 2;
900  layerDesc.m_PadTop = 1;
901  layerDesc.m_PadBottom = 1;
902  layerDesc.m_StrideX = 2;
903  layerDesc.m_StrideY = 3;
905  layerDesc.m_DataLayout = dataLayout;
906 
907  Pooling2dLayer* const layer = graph.AddLayer<Pooling2dLayer>(layerDesc, "layer");
908 
909  // Create extra layers
910  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
911  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
912 
913  TensorShape inputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{3, 2, 5, 5} : TensorShape{3, 5, 5, 2};
914  TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{3, 2, 2, 4} : TensorShape{3, 2, 4, 2};
915 
916  // Connect up
917  Connect(input, layer, TensorInfo(inputShape, DataType));
918  Connect(layer, output, TensorInfo(outputShape, DataType));
919  CreateTensorHandles(graph, factory);
920 
921  // Make the workload and checks it
922  auto workload = MakeAndCheckWorkload<Pooling2dWorkload>(*layer, factory);
923 
924  Pooling2dQueueDescriptor queueDescriptor = workload->GetData();
925  BOOST_TEST((queueDescriptor.m_Parameters.m_PoolType == PoolingAlgorithm::Average));
926  BOOST_TEST((queueDescriptor.m_Parameters.m_OutputShapeRounding == OutputShapeRounding::Floor));
927  BOOST_TEST(queueDescriptor.m_Parameters.m_PoolWidth == 3);
928  BOOST_TEST(queueDescriptor.m_Parameters.m_PoolHeight == 3);
929  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideX == 2);
930  BOOST_TEST(queueDescriptor.m_Parameters.m_StrideY == 3);
931  BOOST_TEST(queueDescriptor.m_Parameters.m_PadLeft == 2);
932  BOOST_TEST(queueDescriptor.m_Parameters.m_PadRight == 2);
933  BOOST_TEST(queueDescriptor.m_Parameters.m_PadTop == 1);
934  BOOST_TEST(queueDescriptor.m_Parameters.m_PadBottom == 1);
935  BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
936 
937  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
938  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
939 
940  // Return so we can do extra, backend-specific tests
941  return workload;
942 }
943 
944 template <typename SoftmaxWorkload, armnn::DataType DataType>
945 std::unique_ptr<SoftmaxWorkload> CreateSoftmaxWorkloadTest(armnn::IWorkloadFactory& factory,
946  armnn::Graph& graph)
947 {
948  // Create the layer we're testing.
949  SoftmaxDescriptor softmaxDescriptor;
950  // Set Axis to 1 if CL or Neon until further Axes are supported.
952  {
953  softmaxDescriptor.m_Axis = 1;
954  }
955 
956  Layer* const layer = graph.AddLayer<SoftmaxLayer>(softmaxDescriptor, "layer");
957  // Create extra layers.
958  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
959  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
960 
961  // Connect up
962  armnn::TensorInfo tensorInfo({4, 1}, DataType);
963  if (DataType == armnn::DataType::QAsymmU8)
964  {
965  tensorInfo.SetQuantizationOffset(0);
966  tensorInfo.SetQuantizationScale(1.f / 256);
967  }
968  else if (DataType == armnn::DataType::QAsymmS8)
969  {
970  tensorInfo.SetQuantizationOffset(-128);
971  tensorInfo.SetQuantizationScale(1.f / 256);
972  }
973 
974  Connect(input, layer, tensorInfo);
975  Connect(layer, output, tensorInfo);
976  CreateTensorHandles(graph, factory);
977 
978  // Make the workload and checks it.
979  auto workload = MakeAndCheckWorkload<SoftmaxWorkload>(*layer, factory);
980 
981  SoftmaxQueueDescriptor queueDescriptor = workload->GetData();
982  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
983  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
984 
985  // Return so we can do extra, backend-specific tests.
986  return workload;
987 }
988 
989 template<typename SplitterWorkload, armnn::DataType DataType>
990 std::unique_ptr<SplitterWorkload>
991  CreateSplitterWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
992 {
993  // Create the layer we're testing.
994  // NOTE: need three dimensions channels, height/y, width/x because the Compute
995  // library restricts subtensors to have the same x and y dimensions as
996  // their parent tensors, and therefore the origin on the x and y dimension
997  // has to be zero for any view. So we need a third dimension to split...
998  // NOTE: arguments are: number of views, number of dimensions.
999  ViewsDescriptor layerDesc(3, 3);
1000  // NOTE: arguments are: view, dimension, value.
1001  layerDesc.SetViewOriginCoord(0, 0, 0);
1002  layerDesc.SetViewOriginCoord(1, 0, 1);
1003  layerDesc.SetViewOriginCoord(2, 0, 3);
1004 
1005  Layer* const layer = graph.AddLayer<SplitterLayer>(layerDesc, "layer");
1006 
1007  // Adds extra layers.
1008  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1009  Layer* const output0 = graph.AddLayer<OutputLayer>(0, "output0");
1010  Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
1011  Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
1012 
1013  // Connects up.
1014  armnn::TensorInfo tensorInfo({5, 7, 7}, DataType);
1015  Connect(input, layer, tensorInfo);
1016 
1017  armnn::TensorInfo output0Info({1, 7, 7}, DataType);
1018  armnn::TensorInfo output1Info({2, 7, 7}, DataType);
1019  armnn::TensorInfo output2Info({2, 7, 7}, DataType);
1020 
1021  Connect(layer, output0, output0Info, 0, 0);
1022  Connect(layer, output1, output1Info, 1, 0);
1023  Connect(layer, output2, output2Info, 2, 0);
1024 
1025  CreateTensorHandles(graph, factory);
1026 
1027  // Makes the workload and checks it.
1028  auto workload = MakeAndCheckWorkload<SplitterWorkload>(*layer, factory);
1029 
1030  SplitterQueueDescriptor queueDescriptor = workload->GetData();
1031  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1032  BOOST_TEST(queueDescriptor.m_Outputs.size() == 3);
1033  BOOST_TEST(queueDescriptor.m_ViewOrigins.size() == 3);
1034 
1035  BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[0] == 0);
1036  BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[0] == 1);
1037  BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[0] == 3);
1038  BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[1] == 0);
1039  BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[1] == 0);
1040  BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[1] == 0);
1041  BOOST_TEST(queueDescriptor.m_ViewOrigins[0].m_Origin[2] == 0);
1042  BOOST_TEST(queueDescriptor.m_ViewOrigins[1].m_Origin[2] == 0);
1043  BOOST_TEST(queueDescriptor.m_ViewOrigins[2].m_Origin[2] == 0);
1044 
1045  // Returns so we can do extra, backend-specific tests.
1046  return workload;
1047 }
1048 
1049 /// This function constructs a graph with both a splitter and a concat, and returns a pair of the workloads.
1050 template<typename SplitterWorkload, typename ConcatWorkload, armnn::DataType DataType>
1051 std::pair<std::unique_ptr<SplitterWorkload>, std::unique_ptr<ConcatWorkload>>
1052  CreateSplitterConcatWorkloadTest(armnn::IWorkloadFactory &factory, armnn::Graph &graph)
1053 {
1054  armnn::TensorInfo inputTensorInfo({ 1, 2, 100, 10 }, DataType);
1055 
1056  armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 10 }, DataType);
1057  armnn::TensorInfo splitTensorInfo2({ 1, 1, 100, 10 }, DataType);
1058 
1059  //Constructs the graph.
1060  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1061 
1062  armnn::ViewsDescriptor splitterViews(2);
1063  splitterViews.SetViewOriginCoord(0, 0, 0);
1064  splitterViews.SetViewOriginCoord(0, 1, 0);
1065  splitterViews.SetViewOriginCoord(0, 2, 0);
1066  splitterViews.SetViewOriginCoord(0, 3, 0);
1067 
1068  splitterViews.SetViewOriginCoord(1, 0, 0);
1069  splitterViews.SetViewOriginCoord(1, 1, 1);
1070  splitterViews.SetViewOriginCoord(1, 2, 0);
1071  splitterViews.SetViewOriginCoord(1, 3, 0);
1072 
1073  Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
1074  BOOST_TEST_CHECKPOINT("created splitter layer");
1075 
1076  armnn::OriginsDescriptor concatViews(2);
1077  concatViews.SetViewOriginCoord(0, 0, 0);
1078  concatViews.SetViewOriginCoord(0, 1, 1);
1079  concatViews.SetViewOriginCoord(0, 2, 0);
1080  concatViews.SetViewOriginCoord(0, 3, 0);
1081 
1082  concatViews.SetViewOriginCoord(1, 0, 0);
1083  concatViews.SetViewOriginCoord(1, 1, 0);
1084  concatViews.SetViewOriginCoord(1, 2, 0);
1085  concatViews.SetViewOriginCoord(1, 3, 0);
1086 
1087  Layer* const concat = graph.AddLayer<ConcatLayer>(concatViews, "concat");
1088  BOOST_TEST_CHECKPOINT("created concat layer");
1089 
1090  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1091 
1092  // Adds connections.
1093  Connect(input, splitter, inputTensorInfo, 0, 0);
1094  BOOST_TEST_CHECKPOINT("connect input to splitter");
1095  Connect(splitter, concat, splitTensorInfo1, 0, 1); // The splitter & concat are connected up.
1096  BOOST_TEST_CHECKPOINT("connect splitter[0] to concat[1]");
1097  Connect(splitter, concat, splitTensorInfo2, 1, 0); // So that the outputs are flipped round.
1098  BOOST_TEST_CHECKPOINT("connect splitter[1] to concat[0]");
1099  Connect(concat, output, inputTensorInfo, 0, 0);
1100  BOOST_TEST_CHECKPOINT("connect concat to output");
1101 
1102  CreateTensorHandles(graph, factory);
1103  BOOST_TEST_CHECKPOINT("created tensor handles");
1104 
1105  auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, factory);
1106  BOOST_TEST_CHECKPOINT("created splitter workload");
1107  auto workloadConcat = MakeAndCheckWorkload<ConcatWorkload>(*concat, factory);
1108  BOOST_TEST_CHECKPOINT("created concat workload");
1109 
1110  return {std::move(workloadSplitter), std::move(workloadConcat)};
1111 }
1112 
1113 
1114 /// This function constructs a graph with a splitter with two outputs. Each of the outputs is then
1115 /// connected to two different activation layers
1116 template<typename SplitterWorkload, typename ActivationWorkload, armnn::DataType DataType>
1117 void CreateSplitterMultipleInputsOneOutputWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph,
1118  std::unique_ptr<SplitterWorkload>& wlSplitter,
1119  std::unique_ptr<ActivationWorkload>& wlActiv0_0,
1120  std::unique_ptr<ActivationWorkload>& wlActiv0_1,
1121  std::unique_ptr<ActivationWorkload>& wlActiv1_0,
1122  std::unique_ptr<ActivationWorkload>& wlActiv1_1)
1123 {
1124  armnn::TensorInfo inputTensorInfo ({ 1, 3, 100, 50 }, DataType);
1125  armnn::TensorInfo splitTensorInfo1({ 1, 1, 100, 50 }, DataType);
1126  armnn::TensorInfo splitTensorInfo2({ 1, 2, 100, 50 }, DataType);
1127 
1128  //Constructs the graph.
1129  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1130 
1131  armnn::ViewsDescriptor splitterViews(2);
1132 
1133  splitterViews.SetViewOriginCoord(0, 0, 0);
1134  splitterViews.SetViewOriginCoord(0, 1, 0);
1135  splitterViews.SetViewOriginCoord(0, 2, 0);
1136  splitterViews.SetViewOriginCoord(0, 3, 0);
1137 
1138  splitterViews.SetViewOriginCoord(1, 0, 0);
1139  splitterViews.SetViewOriginCoord(1, 1, 1);
1140  splitterViews.SetViewOriginCoord(1, 2, 0);
1141  splitterViews.SetViewOriginCoord(1, 3, 0);
1142 
1143  Layer* const splitter = graph.AddLayer<SplitterLayer>(splitterViews, "splitter");
1144 
1145  armnn::ActivationDescriptor activationDesc;
1146 
1147  Layer* const activ0_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_0");
1148  Layer* const activ0_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ0_1");
1149  Layer* const activ1_0 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_0");
1150  Layer* const activ1_1 = graph.AddLayer<ActivationLayer>(activationDesc, "activ1_1");
1151 
1152  Layer* const output1 = graph.AddLayer<OutputLayer>(1, "output1");
1153  Layer* const output2 = graph.AddLayer<OutputLayer>(2, "output2");
1154  Layer* const output3 = graph.AddLayer<OutputLayer>(3, "output3");
1155  Layer* const output4 = graph.AddLayer<OutputLayer>(4, "output4");
1156 
1157  // Adds connections.
1158  Connect(input, splitter, inputTensorInfo, 0, 0);
1159  Connect(splitter, activ0_0, splitTensorInfo1, 0, 0);
1160  Connect(splitter, activ0_1, splitTensorInfo1, 0, 0);
1161 
1162  Connect(splitter, activ1_0, splitTensorInfo2, 1, 0);
1163  Connect(splitter, activ1_1, splitTensorInfo2, 1, 0);
1164 
1165  Connect(activ0_0, output1, splitTensorInfo1, 0, 0);
1166  Connect(activ0_1, output2, splitTensorInfo1, 0, 0);
1167  Connect(activ1_0, output3, splitTensorInfo2, 0, 0);
1168  Connect(activ1_1, output4, splitTensorInfo2, 0, 0);
1169 
1170  CreateTensorHandles(graph, factory);
1171 
1172  auto workloadSplitter = MakeAndCheckWorkload<SplitterWorkload>(*splitter, factory);
1173  auto workloadActiv0_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_0, factory);
1174  auto workloadActiv0_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ0_1, factory);
1175  auto workloadActiv1_0 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_0, factory);
1176  auto workloadActiv1_1 = MakeAndCheckWorkload<ActivationWorkload>(*activ1_1, factory);
1177 
1178  wlSplitter = std::move(workloadSplitter);
1179  wlActiv0_0 = std::move(workloadActiv0_0);
1180  wlActiv0_1 = std::move(workloadActiv0_1);
1181  wlActiv1_0 = std::move(workloadActiv1_0);
1182  wlActiv1_1 = std::move(workloadActiv1_1);
1183 }
1184 
1185 template <typename ResizeWorkload, armnn::DataType DataType>
1186 std::unique_ptr<ResizeWorkload> CreateResizeBilinearWorkloadTest(armnn::IWorkloadFactory& factory,
1187  armnn::Graph& graph,
1188  DataLayout dataLayout = DataLayout::NCHW)
1189 {
1190  TensorShape inputShape;
1191  TensorShape outputShape;
1192 
1193  switch (dataLayout) {
1194  case DataLayout::NHWC:
1195  inputShape = { 2, 4, 4, 3 };
1196  outputShape = { 2, 2, 2, 3 };
1197  break;
1198  case DataLayout::NCHW:
1199  default:
1200  inputShape = { 2, 3, 4, 4 };
1201  outputShape = { 2, 3, 2, 2 };
1202  }
1203 
1204  // Creates the layer we're testing.
1205  ResizeDescriptor resizeDesc;
1206  armnnUtils::DataLayoutIndexed dimensionIndices = dataLayout;
1207  resizeDesc.m_Method = ResizeMethod::Bilinear;
1208  resizeDesc.m_TargetWidth = outputShape[dimensionIndices.GetWidthIndex()];
1209  resizeDesc.m_TargetHeight = outputShape[dimensionIndices.GetHeightIndex()];
1210  resizeDesc.m_DataLayout = dataLayout;
1211  Layer* const layer = graph.AddLayer<ResizeLayer>(resizeDesc, "resize");
1212 
1213  // Creates extra layers.
1214  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1215  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1216 
1217  // Connects up.
1218  armnn::TensorInfo inputTensorInfo(inputShape, DataType);
1219  armnn::TensorInfo outputTensorInfo(outputShape, DataType);
1220  Connect(input, layer, inputTensorInfo);
1221  Connect(layer, output, outputTensorInfo);
1222  CreateTensorHandles(graph, factory);
1223 
1224  // Makes the workload and checks it.
1225  auto workload = MakeAndCheckWorkload<ResizeWorkload>(*layer, factory);
1226 
1227  auto queueDescriptor = workload->GetData();
1228  BOOST_CHECK(queueDescriptor.m_Inputs.size() == 1);
1229  BOOST_CHECK(queueDescriptor.m_Outputs.size() == 1);
1230  BOOST_CHECK(queueDescriptor.m_Parameters.m_DataLayout == dataLayout);
1231 
1232  // Returns so we can do extra, backend-specific tests.
1233  return workload;
1234 }
1235 
1236 template <typename BatchToSpaceNdWorkload, armnn::DataType DataType>
1237 std::unique_ptr<BatchToSpaceNdWorkload> CreateBatchToSpaceNdWorkloadTest(armnn::IWorkloadFactory& factory,
1238  armnn::Graph& graph)
1239 {
1241  Layer* const layer = graph.AddLayer<BatchToSpaceNdLayer>(desc, "batchToSpace");
1242 
1243  // Creates extra layers.
1244  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1245  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1246 
1247  // Connects up.
1248  armnn::TensorInfo tensorInfo({1, 1, 1, 1}, DataType);
1249 
1250  Connect(input, layer, tensorInfo);
1251  Connect(layer, output, tensorInfo);
1252 
1253  CreateTensorHandles(graph, factory);
1254 
1255  // Makes the workload and checks it.
1256  auto workload = MakeAndCheckWorkload<BatchToSpaceNdWorkload>(*layer, factory);
1257 
1258  BatchToSpaceNdQueueDescriptor queueDescriptor = workload->GetData();
1259  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1260  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1261 
1262  return workload;
1263 }
1264 
1265 template <typename L2NormalizationWorkload, armnn::DataType DataType>
1266 std::unique_ptr<L2NormalizationWorkload> CreateL2NormalizationWorkloadTest(armnn::IWorkloadFactory& factory,
1267  armnn::Graph& graph, DataLayout dataLayout = DataLayout::NCHW)
1268 {
1269  // Creates the layer we're testing.
1270  L2NormalizationDescriptor layerDesc;
1271  layerDesc.m_DataLayout = dataLayout;
1272 
1273  Layer* const layer = graph.AddLayer<L2NormalizationLayer>(layerDesc, "l2norm");
1274 
1275  // Creates extra layers.
1276  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1277  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1278 
1279  TensorShape inputShape = (dataLayout == DataLayout::NCHW) ?
1280  TensorShape{ 5, 20, 50, 67 } : TensorShape{ 5, 50, 67, 20 };
1281  TensorShape outputShape = (dataLayout == DataLayout::NCHW) ?
1282  TensorShape{ 5, 20, 50, 67 } : TensorShape{ 5, 50, 67, 20 };
1283 
1284  // Connects up.
1285  armnn::TensorInfo inputTensorInfo(inputShape, DataType);
1286  armnn::TensorInfo outputTensorInfo(outputShape, DataType);
1287  Connect(input, layer, inputTensorInfo);
1288  Connect(layer, output, outputTensorInfo);
1289  CreateTensorHandles(graph, factory);
1290 
1291  // Makes the workload and checks it.
1292  auto workload = MakeAndCheckWorkload<L2NormalizationWorkload>(*layer, factory);
1293 
1294  L2NormalizationQueueDescriptor queueDescriptor = workload->GetData();
1295  BOOST_TEST((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
1296  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1297  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1298 
1299  // Returns so we can do extra, backend-specific tests.
1300  return workload;
1301 }
1302 
1303 template <typename ReshapeWorkload, armnn::DataType DataType>
1304 std::unique_ptr<ReshapeWorkload> CreateReshapeWorkloadTest(armnn::IWorkloadFactory& factory,
1305  armnn::Graph& graph)
1306 {
1307  // Creates the layer we're testing.
1308  TensorShape outputShape({ 1, 4 });
1309  ReshapeDescriptor reshapeDesc;
1310  reshapeDesc.m_TargetShape = outputShape;
1311  Layer* const layer = graph.AddLayer<ReshapeLayer>(reshapeDesc, "layer");
1312 
1313  // Creates extra layers.
1314  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1315  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1316 
1317  // Connects up.
1318  armnn::TensorInfo inputTensorInfo({ 4, 1 }, DataType);
1319  armnn::TensorInfo outputTensorInfo(outputShape, DataType);
1320  Connect(input, layer, inputTensorInfo);
1321  Connect(layer, output, outputTensorInfo);
1322  CreateTensorHandles(graph, factory);
1323 
1324  // Makes the workload and checks it.
1325  auto workload = MakeAndCheckWorkload<ReshapeWorkload>(*layer, factory);
1326 
1327  ReshapeQueueDescriptor queueDescriptor = workload->GetData();
1328  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1329  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1330 
1331  // Returns so we can do extra, backend-specific tests.
1332  return workload;
1333 }
1334 
1335 template <typename ConvertFp16ToFp32Float32Workload>
1336 std::unique_ptr<ConvertFp16ToFp32Float32Workload> CreateConvertFp16ToFp32WorkloadTest(
1337  armnn::IWorkloadFactory& factory, armnn::Graph& graph)
1338 {
1339  // Creates the layer we're testing.
1340  ConvertFp16ToFp32Layer* const layer = graph.AddLayer<ConvertFp16ToFp32Layer>("Fp16ToFp32Converter");
1341 
1342  // Creates extra layers.
1343  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1344  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1345 
1346  // Connects up.
1347  armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
1348  armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
1349  Connect(input, layer, inputTensorInfo);
1350  Connect(layer, output, outputTensorInfo);
1351  CreateTensorHandles(graph, factory);
1352 
1353  // Makes the workload and checks it.
1354  auto workload = MakeAndCheckWorkload<ConvertFp16ToFp32Float32Workload>(*layer, factory);
1355 
1356  ConvertFp16ToFp32QueueDescriptor queueDescriptor = workload->GetData();
1357  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1358  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1359 
1360  // Returns so we can do extra, backend-specific tests.
1361  return workload;
1362 }
1363 
1364 template <typename ConvertFp32ToFp16Float16Workload>
1365 std::unique_ptr<ConvertFp32ToFp16Float16Workload> CreateConvertFp32ToFp16WorkloadTest(
1366  armnn::IWorkloadFactory& factory, armnn::Graph& graph)
1367 {
1368  // Creates the layer we're testing.
1369  ConvertFp32ToFp16Layer* const layer = graph.AddLayer<ConvertFp32ToFp16Layer>("Fp32ToFp16Converter");
1370 
1371  // Creates extra layers.
1372  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1373  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1374 
1375  // Connects up.
1376  armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float32);
1377  armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, armnn::DataType::Float16);
1378  Connect(input, layer, inputTensorInfo);
1379  Connect(layer, output, outputTensorInfo);
1380  CreateTensorHandles(graph, factory);
1381 
1382  // Makes the workload and checks it.
1383  auto workload = MakeAndCheckWorkload<ConvertFp32ToFp16Float16Workload>(*layer, factory);
1384 
1385  ConvertFp32ToFp16QueueDescriptor queueDescriptor = workload->GetData();
1386  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1387  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1388 
1389  // Returns so we can do extra, backend-specific tests.
1390  return workload;
1391 }
1392 
1393 template <typename MeanWorkload, armnn::DataType DataType>
1394 std::unique_ptr<MeanWorkload> CreateMeanWorkloadTest(armnn::IWorkloadFactory& factory, armnn::Graph& graph)
1395 {
1396  // Reduce along the first and second dimensions, and do not keep the reduced dimensions.
1397  MeanDescriptor descriptor({ 1, 2 }, false);
1398 
1399  // Creates the layer we're testing.
1400  Layer* const layer = graph.AddLayer<MeanLayer>(descriptor, "mean");
1401 
1402  // Creates extra layers.
1403  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1404  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1405 
1406  // Connects up.
1407  armnn::TensorInfo inputTensorInfo({ 1, 3, 7, 4 }, DataType);
1408  armnn::TensorInfo outputTensorInfo({ 1, 4 }, DataType);
1409  Connect(input, layer, inputTensorInfo);
1410  Connect(layer, output, outputTensorInfo);
1411  CreateTensorHandles(graph, factory);
1412 
1413  // Makes the workload and checks it.
1414  auto workload = MakeAndCheckWorkload<MeanWorkload>(*layer, factory);
1415 
1416  MeanQueueDescriptor queueDescriptor = workload->GetData();
1417  BOOST_TEST(queueDescriptor.m_Parameters.m_Axis == descriptor.m_Axis);
1418  BOOST_TEST(queueDescriptor.m_Parameters.m_KeepDims == descriptor.m_KeepDims);
1419  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1420  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1421 
1422  // Returns so we can do extra, backend-specific tests.
1423  return workload;
1424 }
1425 
1426 template<typename ConcatWorkload, armnn::DataType DataType>
1427 std::unique_ptr<ConcatWorkload> CreateConcatWorkloadTest(armnn::IWorkloadFactory &factory,
1428  armnn::Graph &graph,
1429  const armnn::TensorShape &outputShape,
1430  unsigned int concatAxis)
1431 {
1432  armnn::TensorInfo inputTensorInfo({ 2, 3, 2, 5 }, DataType);
1433  armnn::TensorInfo outputTensorInfo(outputShape, DataType);
1434 
1435  // Constructs the graph.
1436  Layer* const input0 = graph.AddLayer<InputLayer>(0, "input0");
1437  Layer* const input1 = graph.AddLayer<InputLayer>(1, "input1");
1438  armnn::OriginsDescriptor descriptor;
1439 
1440  std::vector<armnn::TensorShape> inputShapes{{ 2, 3, 2, 5 }, { 2, 3, 2, 5 }};
1441 
1442  descriptor = CreateDescriptorForConcatenation(inputShapes.begin(),
1443  inputShapes.end(),
1444  concatAxis);
1445 
1446  Layer* const concat = graph.AddLayer<ConcatLayer>(descriptor, "concat");
1447  BOOST_TEST_CHECKPOINT("created concat layer");
1448 
1449  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1450 
1451  // Adds connections.
1452  Connect(input0, concat, inputTensorInfo, 0, 0);
1453  BOOST_TEST_CHECKPOINT("connect input0 to concat");
1454  Connect(input1, concat, inputTensorInfo, 0, 1);
1455  BOOST_TEST_CHECKPOINT("connect input1 to concat");
1456  Connect(concat, output, outputTensorInfo, 0, 0);
1457  BOOST_TEST_CHECKPOINT("connect concat to output");
1458 
1459  CreateTensorHandles(graph, factory);
1460  BOOST_TEST_CHECKPOINT("created tensor handles");
1461 
1462  auto workloadConcat = MakeAndCheckWorkload<ConcatWorkload>(*concat, factory);
1463  BOOST_TEST_CHECKPOINT("created concat workload");
1464 
1465  return workloadConcat;
1466 }
1467 
1468 template <typename PreCompiledWorkload, armnn::DataType dataType>
1469 std::pair<armnn::IOptimizedNetworkPtr, std::unique_ptr<PreCompiledWorkload>> CreatePreCompiledWorkloadTest(
1470  armnn::IWorkloadFactory& factory,
1471  armnn::Graph& graph,
1472  bool biasEnabled = false)
1473 {
1474  IgnoreUnused(graph);
1475 
1476  // To create a PreCompiled layer, create a network and Optimize it.
1477  armnn::Network net;
1478 
1479  // Add an input layer
1480  armnn::IConnectableLayer* const inputLayer = net.AddInputLayer(0, "input layer");
1481  BOOST_TEST(inputLayer);
1482 
1483  // ArmNN weights tensor shape is OIHW (out channels, in channels, height, width) for NCHW
1484  // ArmNN weights tensor shape is OHWI (out channels, height, width, in channels) for NHWC
1485  // this test is using NHWC, so the weights shape is OHWI
1486  TensorInfo weightsTensorInfo(TensorShape({16, 1, 1, 16}), dataType, 0.9f, 0);
1487  unsigned int weightsLength = weightsTensorInfo.GetNumElements();
1488 
1489  using WeightType = armnn::ResolveType<dataType>;
1490  std::vector<WeightType> convWeightsData(weightsLength);
1491  for (unsigned int i = 0; i < weightsLength; ++i)
1492  {
1493  convWeightsData[i] = static_cast<WeightType>(i);
1494  }
1495 
1496  armnn::ConstTensor weights(weightsTensorInfo, convWeightsData);
1497 
1498  // Add a layer that can be used in the PreCompiled layer
1499  armnn::Convolution2dDescriptor convDesc2d;
1500  convDesc2d.m_StrideX = 1;
1501  convDesc2d.m_StrideY = 1;
1502  convDesc2d.m_BiasEnabled = biasEnabled;
1504 
1505  armnn::IConnectableLayer* convLayer = nullptr;
1506  const std::string convLayerName("conv layer");
1507 
1508  if (biasEnabled)
1509  {
1510  constexpr armnn::DataType biasDataType = ( dataType == armnn::DataType::QAsymmU8) ?
1511  armnn::DataType::Signed32 : armnn::DataType::Float32;
1512 
1513  TensorInfo biasTensorInfo(TensorShape({16}), biasDataType, 0.9f * 0.9f, 0);
1514  unsigned int biasLength = biasTensorInfo.GetNumElements();
1515 
1516  using BiasType = armnn::ResolveType<biasDataType>;
1517  std::vector<BiasType> biasData(biasLength);
1518  std::fill(biasData.begin(), biasData.end(), static_cast<BiasType>(0));
1519 
1520  armnn::ConstTensor biases(biasTensorInfo, biasData);
1521 
1522  // Create convolution layer with biases
1523  convLayer = net.AddConvolution2dLayer(convDesc2d,
1524  weights,
1525  Optional<ConstTensor>(biases),
1526  convLayerName.c_str());
1527  }
1528  else
1529  {
1530  // Create convolution layer without biases
1531  convLayer = net.AddConvolution2dLayer(convDesc2d,
1532  weights,
1533  EmptyOptional(),
1534  convLayerName.c_str());
1535  }
1536 
1537  BOOST_TEST(convLayer);
1538 
1539  // Add an output layer
1540  armnn::IConnectableLayer* const outputLayer = net.AddOutputLayer(0, "output layer");
1541  BOOST_TEST(outputLayer);
1542 
1543  // set the tensors in the network (NHWC format)
1544  TensorInfo inputTensorInfo(TensorShape({ 1, 16, 16, 16 }), dataType);
1545  if (dataType == armnn::DataType::QAsymmU8)
1546  {
1547  inputTensorInfo.SetQuantizationOffset(0);
1548  inputTensorInfo.SetQuantizationScale(0.9f);
1549  }
1550 
1551  TensorInfo outputTensorInfo(TensorShape({1, 16, 16, 16}), dataType);
1552  if (dataType == armnn::DataType::QAsymmU8)
1553  {
1554  outputTensorInfo.SetQuantizationOffset(0);
1555  outputTensorInfo.SetQuantizationScale(0.9f);
1556  }
1557 
1558  // Connect the layers
1559  inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
1560  inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
1561 
1562  convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1563  convLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
1564 
1565  // Optimize the network for the backend supported by the factory
1566  std::vector<armnn::BackendId> backends = {factory.GetBackendId()};
1568  armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
1569  armnn::OptimizerOptions optimizerOptions;
1570  armnn::IOptimizedNetworkPtr optimizedNet = armnn::Optimize(net, backends, runtime->GetDeviceSpec(),
1571  optimizerOptions);
1572  BOOST_CHECK(optimizedNet != nullptr);
1573 
1574  // Find the PreCompiled layer in the optimised graph
1575  armnn::Graph& optimisedGraph = static_cast<armnn::OptimizedNetwork*>(optimizedNet.get())->GetGraph();
1576  Layer* preCompiledLayer = nullptr;
1577  for (auto& layer : optimisedGraph)
1578  {
1579  if (layer->GetType() == LayerType::PreCompiled)
1580  {
1581  preCompiledLayer = layer;
1582  }
1583  }
1584  BOOST_CHECK(preCompiledLayer != nullptr);
1585 
1586  // Create the TensorHandles.
1587  CreateTensorHandles(optimisedGraph, factory);
1588 
1589  // Make the workload and check it.
1590  auto workload = MakeAndCheckWorkload<PreCompiledWorkload>(*preCompiledLayer, factory);
1591 
1592  PreCompiledQueueDescriptor queueDescriptor = workload->GetData();
1593  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1594  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1595 
1596  // Returns the workload so we can do extra, backend-specific tests.
1597  // NOTE: We need to return the optimised network as well, otherwise it gets
1598  // out of scope and the tensor handles get destructed
1599  return std::make_pair(std::move(optimizedNet), std::move(workload));
1600 }
1601 
1602 template<typename ConstantWorkload, armnn::DataType DataType>
1603 std::unique_ptr<ConstantWorkload> CreateConstantWorkloadTest(armnn::IWorkloadFactory& factory,
1604  armnn::Graph& graph,
1605  const armnn::TensorShape& outputShape)
1606 {
1607  armnn::TensorInfo outputTensorInfo(outputShape, DataType);
1608 
1609  auto constant = graph.AddLayer<ConstantLayer>("constant");
1610  constant->m_LayerOutput = std::make_unique<ScopedCpuTensorHandle>(outputTensorInfo);
1611  BOOST_TEST_CHECKPOINT("created constant layer");
1612 
1613  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1614 
1615  // Adds connections.
1616  Connect(constant, output, outputTensorInfo, 0, 0);
1617  BOOST_TEST_CHECKPOINT("connect constant to output");
1618 
1619  CreateTensorHandles(graph, factory);
1620  BOOST_TEST_CHECKPOINT("created tensor handles");
1621 
1622  auto workloadConstant = MakeAndCheckWorkload<ConstantWorkload>(*constant, factory);
1623  BOOST_TEST_CHECKPOINT("created Constant workload");
1624 
1625  return workloadConstant;
1626 }
1627 
1628 template <typename PreluWorkload>
1629 std::unique_ptr<PreluWorkload> CreatePreluWorkloadTest(armnn::IWorkloadFactory& factory,
1630  armnn::Graph& graph,
1631  const armnn::TensorShape& inputShape,
1632  const armnn::TensorShape& alphaShape,
1633  const armnn::TensorShape& outputShape,
1634  armnn::DataType dataType)
1635 {
1636  // Creates the PReLU layer
1637  Layer* const layer = graph.AddLayer<PreluLayer>("prelu");
1638  BOOST_CHECK(layer != nullptr);
1639 
1640  // Creates extra layers
1641  Layer* const input = graph.AddLayer<InputLayer> (0, "input");
1642  Layer* const alpha = graph.AddLayer<InputLayer> (1, "alpha");
1643  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1644  BOOST_CHECK(input != nullptr);
1645  BOOST_CHECK(alpha != nullptr);
1646  BOOST_CHECK(output != nullptr);
1647 
1648  // Connects up
1649  armnn::TensorInfo inputTensorInfo (inputShape, dataType);
1650  armnn::TensorInfo alphaTensorInfo (alphaShape, dataType);
1651  armnn::TensorInfo outputTensorInfo(outputShape, dataType);
1652  Connect(input, layer, inputTensorInfo, 0, 0);
1653  Connect(alpha, layer, alphaTensorInfo, 0, 1);
1654  Connect(layer, output, outputTensorInfo, 0, 0);
1655  CreateTensorHandles(graph, factory);
1656 
1657  // Makes the workload and checks it
1658  auto workload = MakeAndCheckWorkload<PreluWorkload>(*layer, factory);
1659 
1660  PreluQueueDescriptor queueDescriptor = workload->GetData();
1661  BOOST_TEST(queueDescriptor.m_Inputs.size() == 2);
1662  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1663 
1664  // Returns so we can do extra, backend-specific tests.
1665  return workload;
1666 }
1667 
1668 template <typename SpaceToDepthWorkload, armnn::DataType DataType>
1669 std::unique_ptr<SpaceToDepthWorkload> CreateSpaceToDepthWorkloadTest(armnn::IWorkloadFactory& factory,
1670  armnn::Graph& graph)
1671 {
1673  desc.m_BlockSize = 2;
1674  Layer* const layer = graph.AddLayer<SpaceToDepthLayer>(desc, "spaceToDepth");
1675 
1676  // Creates extra layers.
1677  Layer* const input = graph.AddLayer<InputLayer>(0, "input");
1678  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1679 
1680  // Connects up.
1681  armnn::TensorInfo inputTensorInfo({ 1, 2, 2, 1 }, DataType);
1682  armnn::TensorInfo outputTensorInfo({ 1, 1, 1, 4 }, DataType);
1683 
1684  Connect(input, layer, inputTensorInfo);
1685  Connect(layer, output, outputTensorInfo);
1686 
1687  CreateTensorHandles(graph, factory);
1688 
1689  // Makes the workload and checks it.
1690  auto workload = MakeAndCheckWorkload<SpaceToDepthWorkload>(*layer, factory);
1691 
1692  SpaceToDepthQueueDescriptor queueDescriptor = workload->GetData();
1693  BOOST_TEST(queueDescriptor.m_Inputs.size() == 1);
1694  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1695 
1696  return workload;
1697 }
1698 
1699 template <typename StackWorkload, armnn::DataType DataType>
1700 std::unique_ptr<StackWorkload> CreateStackWorkloadTest(armnn::IWorkloadFactory& factory,
1701  armnn::Graph& graph,
1702  const armnn::TensorShape& inputShape,
1703  const armnn::TensorShape& outputShape,
1704  unsigned int axis,
1705  unsigned int numInputs)
1706 {
1707  armnn::TensorInfo inputTensorInfo(inputShape, DataType);
1708  armnn::TensorInfo outputTensorInfo(outputShape, DataType);
1709 
1710  // Constructs the Stack layer.
1711  armnn::StackDescriptor descriptor(axis, numInputs, inputShape);
1712  Layer* const stackLayer = graph.AddLayer<StackLayer>(descriptor, "stack");
1713  BOOST_CHECK(stackLayer != nullptr);
1714 
1715  // Constructs layer inputs and output.
1716  std::vector<Layer*> inputs;
1717  for (unsigned int i=0; i<numInputs; ++i)
1718  {
1719  inputs.push_back(graph.AddLayer<InputLayer>(
1720  static_cast<int>(i),
1721  ("input" + std::to_string(i)).c_str()
1722  ));
1723  BOOST_CHECK(inputs[i] != nullptr);
1724  }
1725  Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
1726  BOOST_CHECK(output != nullptr);
1727 
1728  // Adds connections.
1729  for (unsigned int i=0; i<numInputs; ++i)
1730  {
1731  Connect(inputs[i], stackLayer, inputTensorInfo, 0, i);
1732  }
1733  Connect(stackLayer, output, outputTensorInfo, 0, 0);
1734 
1735  CreateTensorHandles(graph, factory);
1736 
1737  auto stackWorkload = MakeAndCheckWorkload<StackWorkload>(*stackLayer, factory);
1738  StackQueueDescriptor queueDescriptor = stackWorkload->GetData();
1739  BOOST_TEST(queueDescriptor.m_Inputs.size() == numInputs);
1740  BOOST_TEST(queueDescriptor.m_Outputs.size() == 1);
1741 
1742  return stackWorkload;
1743 }
1744 
1745 } // Anonymous namespace
A layer that the constant data can be bound to.
std::unique_ptr< ScopedCpuTensorHandle > m_ForgetGateBias
A unique pointer to represent 1D weights tensor with dimensions [num_units].
Definition: LstmLayer.hpp:69
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
std::unique_ptr< ScopedCpuTensorHandle > m_InputToOutputWeights
A unique pointer to represent 2D weights tensor with dimensions [input_size, num_units].
Definition: LstmLayer.hpp:61
std::unique_ptr< ScopedCpuTensorHandle > m_RecurrentToCellWeights
A unique pointer to represent 2D weights tensor with dimensions [output_size, num_units].
Definition: LstmLayer.hpp:65
bool m_ProjectionEnabled
Enable/disable the projection layer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
This layer represents a split operation.
static IRuntimePtr Create(const CreationOptions &options)
Definition: Runtime.cpp:31
virtual const BackendId & GetBackendId() const =0
LstmBasicParameters m_BasicParameters
Definition: LstmLayer.hpp:81
This layer represents a batch normalization operation.
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:61
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
IConnectableLayer * AddOutputLayer(LayerBindingId id, const char *name=nullptr) override
Adds an output layer to the network.
Definition: Network.cpp:1435
DataLayout
Definition: Types.hpp:49
unsigned int GetWidthIndex() const
float m_K
Kappa value used for the across channel normalization equation.
int m_Axis
Scalar, defaulted to the last index (-1), specifying the dimension the activation will be performed o...
uint32_t m_PadBottom
Padding bottom value in the height dimension.
uint32_t m_PadLeft
Padding left value in the width dimension.
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
float m_ClippingThresProj
Clipping threshold value for the projection.
A ReshapeDescriptor for the ReshapeLayer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
std::unique_ptr< ScopedCpuTensorHandle > m_OutputGateBias
A unique pointer to represent 1D bias tensor with dimensions [num_units] (int32). ...
Definition: QLstmLayer.hpp:35
This layer represents a depthwise convolution 2d operation.
std::unique_ptr< ScopedCpuTensorHandle > m_CellLayerNormWeights
A unique pointer to represent 1D weights tensor with dimensions [num_units] (QSymmS16).
Definition: QLstmLayer.hpp:73
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Definition: Graph.hpp:398
bool m_TransposeWeightMatrix
Enable/disable transpose weight matrix.
std::unique_ptr< ScopedCpuTensorHandle > m_Bias
A unique pointer to store Bias values.
uint32_t m_PoolWidth
Pooling width value.
bool m_PeepholeEnabled
Enable/disable peephole.
A Convolution2dDescriptor for the Convolution2dLayer.
float m_Alpha
Alpha value for the normalization equation.
uint32_t m_PadLeft
Padding left value in the width dimension.
std::unique_ptr< ScopedCpuTensorHandle > m_RecurrentToForgetWeights
A unique pointer to represent 2D weights tensor with dimensions [output_size, num_units].
Definition: LstmLayer.hpp:63
This layer converts data type Float 16 to Float 32.
float m_HiddenStateScale
Hidden State quantization scale.
float m_OutputIntermediateScale
Output intermediate quantization scale.
ResizeMethod m_Method
The Interpolation method to use (Bilinear, NearestNeighbor).
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
Definition: IRuntime.hpp:25
float m_Eps
Value to add to the variance. Used to avoid dividing by zero.
This layer represents a SpaceToDepth operation.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
IConnectableLayer * AddInputLayer(LayerBindingId id, const char *name=nullptr) override
Adds an input layer to the network.
Definition: Network.cpp:1166
std::unique_ptr< ScopedCpuTensorHandle > m_Gamma
A unique pointer to store Gamma values.
std::unique_ptr< ScopedCpuTensorHandle > m_OutputGateBias
A unique pointer to represent 1D weights tensor with dimensions [num_units].
Definition: LstmLayer.hpp:73
This layer represents a reshape operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Variance
A unique pointer to store Variance values.
std::unique_ptr< ScopedCpuTensorHandle > m_InputToForgetWeights
A unique pointer to represent 2D weights tensor with dimensions [num_units, inputSize] (QSymmS8)...
Definition: QLstmLayer.hpp:17
std::unique_ptr< ScopedCpuTensorHandle > m_CellBias
A unique pointer to represent 1D bias tensor with dimensions [num_units] (int32). ...
Definition: QLstmLayer.hpp:33
typename ResolveTypeImpl< DT >::Type ResolveType
Definition: ResolveType.hpp:73
This layer represents an activation operation with the specified activation function.
uint32_t m_PadTop
Padding top value in the height dimension.
uint32_t m_PadRight
Padding right value in the width dimension.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
Copyright (c) 2020 ARM Limited.
This layer represents a LSTM operation.
Definition: LstmLayer.hpp:77
void IgnoreUnused(Ts &&...)
std::unique_ptr< ScopedCpuTensorHandle > m_InputToOutputWeights
A unique pointer to represent 2D weights tensor with dimensions [num_units, inputSize] (QSymmS8)...
Definition: QLstmLayer.hpp:21
void SetBackendId(const BackendId &id)
Definition: Layer.hpp:264
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
std::unique_ptr< ScopedCpuTensorHandle > m_OutputLayerNormWeights
A unique pointer to represent 1D weights tensor with dimensions [num_units] (QSymmS16).
Definition: QLstmLayer.hpp:75
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
std::unique_ptr< ScopedCpuTensorHandle > m_CellBias
A unique pointer to represent 1D weights tensor with dimensions [num_units].
Definition: LstmLayer.hpp:71
unsigned int GetHeightIndex() const
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
QLstmOptLayerNormParameters m_LayerNormParameters
Definition: QLstmLayer.hpp:87
NormalizationAlgorithmMethod m_NormMethodType
Normalization method algorithm to use (LocalBrightness, LocalContrast).
This layer represents a elementwiseUnary operation.
A ResizeDescriptor for the ResizeLayer.
std::unique_ptr< ScopedCpuTensorHandle > m_Beta
A unique pointer to store Beta values.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
IConnectableLayer * AddConvolution2dLayer(const Convolution2dDescriptor &convolution2dDescriptor, const ConstTensor &weights, const Optional< ConstTensor > &biases, const char *name=nullptr) override
Adds a 2D convolution layer to the network.
Definition: Network.cpp:1264
A StackDescriptor for the StackLayer.
TensorShape m_TargetShape
Target shape value.
std::unique_ptr< ScopedCpuTensorHandle > m_RecurrentToForgetWeights
A unique pointer to represent 2D weights tensor with dimensions [num_units, outputSize] (QSymmS8)...
Definition: QLstmLayer.hpp:24
uint32_t m_PoolHeight
Pooling height value.
uint32_t m_PadTop
Padding top value in the height dimension.
std::unique_ptr< ScopedCpuTensorHandle > m_CellToForgetWeights
A unique pointer to represent 1D weights tensor with dimensions [num_units].
Definition: LstmLayer.hpp:49
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
std::unique_ptr< ScopedCpuTensorHandle > m_LayerOutput
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
bool m_LayerNormEnabled
Enable/disable layer normalization.
DataType
Definition: Types.hpp:32
This layer represents a fully connected operation.
An LstmDescriptor for the LstmLayer.
uint32_t m_PadRight
Padding right value in the width dimension.
uint32_t m_PadTop
Padding top value in the height dimension.
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Create an optimized version of the network.
Definition: Network.cpp:1003
This layer represents a QuantizedLstm operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Mean
A unique pointer to store Mean values.
A L2NormalizationDescriptor for the L2NormalizationLayer.
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout...
An OriginsDescriptor for the ConcatLayer.
float m_ProjectionClip
Clipping threshold value for the projection.
A FullyConnectedDescriptor for the FullyConnectedLayer.
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
bool m_BiasEnabled
Enable/disable bias.
This layer represents a stack operation.
Definition: StackLayer.hpp:13
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:199
float m_InputIntermediateScale
Input intermediate quantization scale.
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
This layer represents a softmax operation.
uint32_t m_TargetWidth
Target width value.
bool m_PeepholeEnabled
Enable/disable peephole.
This layer represents a BatchToSpaceNd operation.
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:573
A QLstmDescriptor for the QLstmLayer.
std::unique_ptr< ScopedCpuTensorHandle > m_ForgetLayerNormWeights
A unique pointer to represent 1D weights tensor with dimensions [num_units] (QSymmS16).
Definition: QLstmLayer.hpp:71
GPU Execution: OpenCL: ArmCompute.
static bool IsLayerSupported(const BackendId &backendId, const IConnectableLayer &layer, Optional< DataType > dataType, std::string &outReasonIfUnsupported)
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
uint32_t m_TargetHeight
Target height value.
uint32_t m_ActivationFunc
The activation function to use.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
This layer represents a normalization operation.
This layer represents a pooling 2d operation.
float m_ClippingThresCell
Clipping threshold value for the cell state.
This layer converts data type Float 32 to Float 16.
unsigned int m_BlockSize
Scalar specifying the input block size. It must be >= 1.
DataType GetBiasDataType(DataType inputDataType)
std::unique_ptr< ScopedCpuTensorHandle > m_InputToCellWeights
A unique pointer to represent 2D weights tensor with dimensions [num_units, inputSize] (QSymmS8)...
Definition: QLstmLayer.hpp:19
float m_ForgetIntermediateScale
Forget intermediate quantization scale.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
std::unique_ptr< ScopedCpuTensorHandle > m_RecurrentToOutputWeights
A unique pointer to represent 2D weights tensor with dimensions [output_size, num_units].
Definition: LstmLayer.hpp:67
QLstmBasicParameters m_BasicParameters
Definition: QLstmLayer.hpp:83
LstmOptPeepholeParameters m_PeepholeParameters
Definition: LstmLayer.hpp:84
Private implementation of INetwork.
Definition: Network.hpp:28
NormalizationAlgorithmChannel m_NormChannelType
Normalization channel algorithm to use (Across, Within).
This layer represents a QLstm operation.
Definition: QLstmLayer.hpp:79
float m_CellClip
Clipping threshold value for the cell state.
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH, Elu).
Definition: Descriptors.hpp:45
bool m_CifgEnabled
Enable/disable cifg (coupled input & forget gate).
std::unique_ptr< ScopedCpuTensorHandle > m_InputToCellWeights
A unique pointer to represent 2D weights tensor with dimensions [input_size, num_units].
Definition: LstmLayer.hpp:59
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
Definition: Optional.hpp:32
std::unique_ptr< ScopedCpuTensorHandle > m_ForgetGateBias
A unique pointer to represent 1D bias tensor with dimensions [num_units] (int32). ...
Definition: QLstmLayer.hpp:31
A ElementwiseUnaryDescriptor for the ElementwiseUnaryLayer.
Definition: Descriptors.hpp:90
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
This layer represents a L2 normalization operation.
std::unique_ptr< ScopedCpuTensorHandle > m_RecurrentToCellWeights
A unique pointer to represent 2D weights tensor with dimensions [num_units, outputSize] (QSymmS8)...
Definition: QLstmLayer.hpp:26
CPU Execution: NEON: ArmCompute.
bool m_ProjectionEnabled
Enable/disable the projection layer.
OutputShapeRounding m_OutputShapeRounding
The rounding method for the output shape. (Floor, Ceiling).
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
std::unique_ptr< ScopedCpuTensorHandle > m_Bias
A unique pointer to store Bias values.
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
A MeanDescriptor for the MeanLayer.
UnaryOperation
Definition: Types.hpp:87
std::unique_ptr< ScopedCpuTensorHandle > m_CellToOutputWeights
A unique pointer to represent 1D weights tensor with dimensions [num_units].
Definition: LstmLayer.hpp:51
DataType GetDataType() const
Definition: Layer.cpp:274
std::unique_ptr< ScopedCpuTensorHandle > m_RecurrentToOutputWeights
A unique pointer to represent 2D weights tensor with dimensions [num_units, outputSize] (QSymmS8)...
Definition: QLstmLayer.hpp:28
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
This layer represents a convolution 2d operation.
void SetQuantizationOffset(int32_t offset)
Definition: Tensor.cpp:276
void Connect(armnn::IConnectableLayer *from, armnn::IConnectableLayer *to, const armnn::TensorInfo &tensorInfo, unsigned int fromIndex, unsigned int toIndex)
Definition: TestUtils.cpp:12
OriginsDescriptor CreateDescriptorForConcatenation(TensorShapeIt first, TensorShapeIt last, unsigned int concatenationDimension)
Convenience template to create an OriginsDescriptor to use when creating a ConcatLayer for performing...
Graph & TopologicalSort()
Sorts layers in topological order and return this.
Definition: Graph.hpp:174
This layer represents a mean operation.
Definition: MeanLayer.hpp:14
virtual int Connect(IInputSlot &destination)=0
Krichevsky 2012: Local Brightness Normalization.
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
A Pooling2dDescriptor for the Pooling2dLayer.
armnn::Runtime::CreationOptions::ExternalProfilingOptions options
A NormalizationDescriptor for the NormalizationLayer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
virtual void CreateTensorHandles(const TensorHandleFactoryRegistry &registry, const IWorkloadFactory &factory, const bool IsMemoryManaged=true)
Definition: Layer.cpp:241
virtual std::unique_ptr< IWorkload > CreateWorkload(const IWorkloadFactory &factory) const =0
float m_CellIntermediateScale
Cell intermediate quantization scale.
std::unique_ptr< ScopedCpuTensorHandle > m_InputToForgetWeights
A unique pointer to represent 2D weights tensor with dimensions [input_size, num_units].
Definition: LstmLayer.hpp:57
float m_B
Beta lower bound value used by the activation functions. (BoundedReLu, Linear, TanH).
Definition: Descriptors.hpp:47
A SoftmaxDescriptor for the SoftmaxLayer.
float m_Beta
Beta value for the normalization equation.
bool m_CifgEnabled
Enable/disable CIFG (coupled input & forget gate).
uint32_t m_NormSize
Depth radius value.
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu, LeakyReLu, Abs, Sqrt, Square, Elu).
Definition: Descriptors.hpp:43
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
uint32_t m_PadLeft
Padding left value in the width dimension.
This layer represents a resize operation.
Definition: ResizeLayer.hpp:13
uint32_t m_PadRight
Padding right value in the width dimension.
int32_t m_HiddenStateZeroPoint
Hidden State zero point.