ArmNN
 22.02
ConcatTestImpl.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "ConcatTestImpl.hpp"
7 
9 #include <ResolveType.hpp>
10 
11 
12 #include <armnnUtils/Permute.hpp>
13 
16 
18 
19 using namespace armnn;
20 using namespace armnnUtils;
21 
22 //
23 // Helper functions and templates
24 //
25 
27  const std::vector<TensorInfo> & inputTensorInfos,
28  unsigned int concatDim)
29 {
30  std::vector<TensorShape> shapes;
31  shapes.reserve(inputTensorInfos.size());
32  for (const TensorInfo& it: inputTensorInfos)
33  {
34  shapes.push_back(it.GetShape());
35  }
36 
37  return CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), concatDim);
38 }
39 
40 //
41 // Concat is only supported for N and C dimensions for NCHW and the inner most dimension
42 // In case of <4 dimensions we need to make sure that the concat dimensions are at least
43 // the 3rd slowest iterating one or the inner most dimension.
44 //
45 
47  const std::vector<TensorInfo> & inputTensorInfos,
48  unsigned int concatDim)
49 {
50  // See note above. Additionally we expect the input shapes to have the
51  // same number of dimensions.
52  unsigned int nDimensions = 0;
53 
54  // Determine the number of dimensions as well as sanity check them
55  // agains test implementation issues.
56  for (auto && tensorInfo : inputTensorInfos)
57  {
58  if (!nDimensions)
59  {
60  nDimensions = tensorInfo.GetShape().GetNumDimensions();
61  }
62  else
63  {
64  ARMNN_ASSERT_MSG(nDimensions == tensorInfo.GetShape().GetNumDimensions(),
65  "Input shapes must have the same number of dimensions");
66  }
67  }
68 
69  return (nDimensions < 3 || (nDimensions == 3 && (nDimensions-concatDim) < 3 && (nDimensions-concatDim) != 1));
70 }
71 
73 {
74  unsigned int numDims = inputShape.GetNumDimensions();
75  if (numDims >= 3)
76  {
77  // Nothing to do if the inputShape has at least 3 dimensions.
78  return inputShape;
79  }
80 
81  std::vector<unsigned int> newDims(size_t(3), 1u);
82  unsigned int expandedBy = 3 - numDims;
83  for (unsigned int i=0; i<numDims; ++i)
84  {
85  newDims[expandedBy+i] = inputShape[i];
86  }
87  return TensorShape(3u, &newDims[0]);
88 }
89 
91  unsigned int numDimensions,
92  unsigned int & concatDim,
93  std::pair<PermutationVector, PermutationVector> & permutations)
94 {
95  ARMNN_ASSERT_MSG(numDimensions <= 3,
96  "Only dimensions 1,2 and 3 are supported by this helper");
97  unsigned int expandedBy = 3 - numDimensions;
98  unsigned int expandedConcatAxis = concatDim + expandedBy;
99 
100  if (expandedConcatAxis == 2)
101  {
102  concatDim = 0;
103  PermutationVector forwardPermutation({1, 2, 0});
104  PermutationVector reversePermutation({2, 0, 1});
105  permutations = std::make_pair(forwardPermutation, reversePermutation);
106  }
107  else if (expandedConcatAxis == 1)
108  {
109  concatDim = 0;
110  PermutationVector forwardPermutation({2, 0, 1});
111  PermutationVector reversePermutation({1, 2, 0});
112  permutations = std::make_pair(forwardPermutation, reversePermutation);
113  }
114  else
115  {
116  ARMNN_ASSERT(expandedConcatAxis == 0);
117  concatDim = 0;
118  }
119 }
120 
121 template<typename T> void PermuteTensorData(
122  IWorkloadFactory& workloadFactory,
123  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
124  const armnn::ITensorHandleFactory& tensorHandleFactory,
125  const PermutationVector& mappings,
126  TensorInfo & inputTensorInfo,
127  const T * inputData,
128  std::vector<T>& outputData)
129 {
130  IgnoreUnused(memoryManager);
131  ARMNN_ASSERT_MSG(inputData != nullptr, "inputData must not be null");
132  if (inputData == nullptr)
133  {
134  // Nullptr is an error in the test. By returning without doing the concatenation
135  // I expect the caller to fail the test. It still makes sense to report this as
136  // an assert for Debug builds.
137  return;
138  }
139 
140  TensorInfo outputTensorInfo = armnnUtils::Permuted(inputTensorInfo, mappings);
141  std::unique_ptr<ITensorHandle> inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
142  std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
143 
144  PermuteQueueDescriptor queueDescriptor;
145  queueDescriptor.m_Parameters = PermuteDescriptor{mappings};
146  WorkloadInfo workloadInfo;
147  AddInputToWorkload(queueDescriptor, workloadInfo, inputTensorInfo, inputHandle.get());
148  AddOutputToWorkload(queueDescriptor, workloadInfo, outputTensorInfo, outputHandle.get());
149 
150  std::unique_ptr<IWorkload> workload = workloadFactory.CreateWorkload(LayerType::Permute,
151  queueDescriptor,
152  workloadInfo);
153 
154  inputHandle->Allocate();
155  outputHandle->Allocate();
156 
157  CopyDataToITensorHandle(inputHandle.get(), inputData);
158 
159  workload->PostAllocationConfigure();
160  workload->Execute();
161 
162  outputData.resize(outputTensorInfo.GetNumElements());
163  CopyDataFromITensorHandle(&outputData[0], outputHandle.get());
164  inputTensorInfo = outputTensorInfo;
165 }
166 
167 //
168 // Permute the input tensors so we can do a supported concatenation.
169 // Also treat lower than 3d tensors as 3d by adding dummy 1 dimensions
170 // at the front. Finally this function tells what the output shape
171 // of the permuted concatenated tensor is going to be.
172 //
173 template<typename T> void PermuteInputsForConcat(
174  IWorkloadFactory& workloadFactory,
175  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
176  const armnn::ITensorHandleFactory& tensorHandleFactory,
177  std::vector<TensorInfo> & inputTensorInfos,
178  std::vector<T *> & inputData,
179  std::vector<std::vector<T>> & inputDataStorage,
180  PermutationVector & permuteVector,
181  unsigned int & concatDim,
182  TensorInfo & outputTensorInfo)
183 {
184  IgnoreUnused(memoryManager);
185  ARMNN_ASSERT_MSG(inputTensorInfos.size() > 1,
186  "Expecting more than one tensor to be concatenated here");
187 
188  unsigned int numDims = 0;
189  unsigned int nthInput = 0;
190  const PermutationVector identity({0, 1, 2});
191 
192  std::pair<PermutationVector, PermutationVector> permutations =
193  std::make_pair(identity, identity);
194 
195  inputDataStorage.resize(inputData.size());
196 
197  for (auto && tensorInfo : inputTensorInfos)
198  {
199  if (numDims == 0)
200  {
201  numDims = tensorInfo.GetShape().GetNumDimensions();
202  Generate3dPermuteVectorForConcat(numDims, concatDim, permutations);
203 
204  // Store the reverese permutation.
205  permuteVector = permutations.second;
206  ARMNN_ASSERT_MSG(!permuteVector.IsEqual(identity),
207  "Test logic error, we don't need permutation, so we shouldn't arrive here");
208  }
209  else
210  {
211  ARMNN_ASSERT_MSG(numDims == tensorInfo.GetShape().GetNumDimensions(),
212  "All inputs must have the same number of dimensions");
213  }
214 
215  TensorInfo newTensorInfo = tensorInfo;
216  newTensorInfo.SetShape(ExpandTensorShapeTo3dForPermute(tensorInfo.GetShape()));
217 
218  PermuteTensorData<T>(workloadFactory,
219  memoryManager,
220  tensorHandleFactory,
221  permutations.first,
222  newTensorInfo,
223  inputData[nthInput],
224  inputDataStorage[nthInput]);
225 
226  inputData[nthInput] = inputDataStorage[nthInput].data();
227  inputTensorInfos[nthInput] = newTensorInfo;
228 
229  ++nthInput;
230  }
231 
232  outputTensorInfo.SetShape(
234  ExpandTensorShapeTo3dForPermute(outputTensorInfo.GetShape()),
235  permutations.first));
236 }
237 
238 //
239 // This is the pair of PermuteInputsForConcat(...) which permutes back
240 // the output of the concatenation so we can check it against an expected
241 // output.
242 //
243 template <typename T> void PermuteOutputForConcat(
244  IWorkloadFactory& workloadFactory,
245  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
246  const armnn::ITensorHandleFactory& tensorHandleFactory,
247  const TensorInfo & tensorInfo,
248  const PermutationVector & permuteVector,
249  std::unique_ptr<ITensorHandle> && inputDataHandle,
250  T * data)
251 {
252  ARMNN_ASSERT_MSG(data != nullptr, "data must not be null");
253  if (data == nullptr)
254  {
255  // Nullptr is an error in the test. By returning without doing the permutation
256  // I expect the caller to fail the test. It still makes sense to report this as
257  // an assert for Debug builds.
258  return;
259  }
260 
261  TensorInfo resultTensorInfo = tensorInfo;
262  std::vector<T> inputData(tensorInfo.GetNumElements());
263  std::vector<T> outputData;
264 
265  CopyDataFromITensorHandle(&inputData[0], inputDataHandle.get());
266 
267  PermuteTensorData<T>(workloadFactory,
268  memoryManager,
269  tensorHandleFactory,
270  permuteVector,
271  resultTensorInfo,
272  &inputData[0],
273  outputData);
274 
275  ::memcpy(data, &outputData[0], sizeof(T)*outputData.size());
276 }
277 
278 template<typename T> void Concatenate(
279  IWorkloadFactory& workloadFactory,
280  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
281  const armnn::ITensorHandleFactory& tensorHandleFactory,
282  std::initializer_list<const TensorInfo> inputTensorInfosOrig,
283  std::initializer_list<T *> inputsOrig,
284  const TensorInfo& outputTensorInfoOrig,
285  T * output,
286  unsigned int concatDim,
287  bool useSubtensor)
288 {
289  ARMNN_ASSERT_MSG(output != nullptr, "output must not be null");
290  if (output == nullptr)
291  {
292  // Nullptr is an error in the test. By returning without doing the permutation
293  // I expect the caller to fail the test. It still makes sense to report this as
294  // an assert for Debug builds.
295  return;
296  }
297 
298  // Saves a copy of the parameters which we might need to change.
299  std::vector<TensorInfo> inputTensorInfos(inputTensorInfosOrig.begin(), inputTensorInfosOrig.end());
300  std::vector<T *> inputs = inputsOrig;
301  TensorInfo outputTensorInfo = outputTensorInfoOrig;
302 
303  PermutationVector permuteVector{0, 1, 2};
304 
305  // Holds and automatically releases memory for the reshaped input data.
306  std::vector<std::vector<T>> tmpInputDataStorage;
307 
308  const size_t inputCount = inputTensorInfos.size();
309 
310  bool needPermuteForConcat = NeedPermuteForConcat(inputTensorInfos, concatDim);
311 
312  if (needPermuteForConcat)
313  {
314  //
315  // We need to permute the inputs, because concatenation along
316  // the requested axis is not supported.
317  //
318  PermuteInputsForConcat<T>(workloadFactory,
319  memoryManager,
320  tensorHandleFactory,
321  inputTensorInfos,
322  inputs,
323  tmpInputDataStorage,
324  permuteVector,
325  concatDim,
326  outputTensorInfo);
327  }
328 
329  WorkloadInfo workloadInfo;
330 
331  std::vector<std::unique_ptr<ITensorHandle>> inputHandles;
332  inputHandles.reserve(inputCount);
333 
334  std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
335 
336  ConcatQueueDescriptor queueDescriptor;
337  OriginsDescriptor viewsDescriptor = CreateDescriptorForConcat(inputTensorInfos, concatDim);
338  queueDescriptor.m_Parameters = viewsDescriptor;
339 
340  if (useSubtensor)
341  {
342  queueDescriptor.m_ViewOrigins.reserve(viewsDescriptor.GetNumViews());
343  for (unsigned int i = 0; i < viewsDescriptor.GetNumViews(); ++i)
344  {
345  queueDescriptor.m_ViewOrigins.emplace_back(std::vector<unsigned int>(viewsDescriptor.GetViewOrigin(i),
346  viewsDescriptor.GetViewOrigin(i) + viewsDescriptor.GetNumDimensions()));
347  }
348 
349  outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
350 
351  const bool subTensorsSupported = workloadFactory.SupportsSubTensors();
352  for (unsigned int i = 0; i < inputCount; ++i)
353  {
354  const TensorInfo& inputTensorInfo = inputTensorInfos[i];
355 
356  std::unique_ptr<ITensorHandle> inputHandle =
357  subTensorsSupported ?
358  tensorHandleFactory.CreateSubTensorHandle(*outputHandle,
359  inputTensorInfo.GetShape(),
360  queueDescriptor.m_ViewOrigins[i].m_Origin.data()) :
361  tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
362 
363  inputHandles.emplace_back(std::move(inputHandle));
364  }
365 
366 
367  }
368  else
369  {
370  for (unsigned int i = 0; i < inputCount; ++i)
371  {
372  std::unique_ptr<ITensorHandle> inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfos[i]);
373  inputHandles.emplace_back(std::move(inputHandle));
374  }
375  }
376 
377  for (unsigned int i = 0; i < inputCount; ++i)
378  {
379  AddInputToWorkload(queueDescriptor, workloadInfo, inputTensorInfos[i], inputHandles[i].get());
380  }
381 
382  AddOutputToWorkload(queueDescriptor, workloadInfo, outputTensorInfo, outputHandle.get());
383 
384  std::unique_ptr<IWorkload> workload
385  = workloadFactory.CreateWorkload(LayerType::Concat, queueDescriptor, workloadInfo);
386 
387  for (auto& inputHandle : inputHandles)
388  {
389  inputHandle->Allocate();
390  }
391 
392  outputHandle->Allocate();
393 
394  unsigned int nextInputId = 0;
395  for (auto& inputHandle : inputHandles)
396  {
397  CopyDataToITensorHandle(inputHandle.get(), inputs[nextInputId]);
398  ++nextInputId;
399  }
400 
401  workload->PostAllocationConfigure();
402  workload->Execute();
403 
404  if (needPermuteForConcat)
405  {
406  PermuteOutputForConcat<T>(workloadFactory,
407  memoryManager,
408  tensorHandleFactory,
409  outputTensorInfo,
410  permuteVector,
411  std::move(outputHandle),
412  output);
413  }
414  else
415  {
416  CopyDataFromITensorHandle(output, outputHandle.get());
417  }
418 }
419 
420 //
421 // Implementation templates
422 //
423 
424 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
426  IWorkloadFactory& workloadFactory,
427  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
428  const armnn::ITensorHandleFactory& tensorHandleFactory,
429  float qScale,
430  int32_t qOffset)
431 {
432  TensorInfo inputTensorInfo({ 3 }, ArmnnType, qScale, qOffset);
433 
434  auto input0 = QuantizedVector<T>({ 1.0f, 2.0f, 3.0f }, qScale, qOffset);
435  auto input1 = QuantizedVector<T>({ 4.0f, 5.0f, 6.0f }, qScale, qOffset);
436  auto input2 = QuantizedVector<T>({ 7.0f, 8.0f, 9.0f }, qScale, qOffset);
437 
438  TensorInfo outputTensorInfo({ 9 }, ArmnnType, qScale, qOffset);
439 
440  LayerTestResult<T, 1> result(outputTensorInfo);
441 
442  std::vector<T> output;
443  output.resize(outputTensorInfo.GetNumElements());
444  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
445  { inputTensorInfo, inputTensorInfo, inputTensorInfo },
446  { input0.data(), input1.data(), input2.data() },
447  outputTensorInfo,
448  output.data(),
449  0,
450  true);
451 
452  result.m_ActualData = output;
453  result.m_ExpectedData = QuantizedVector<T>(
454  {
455  1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f
456  },
457  qScale, qOffset);
458 
459  return result;
460 }
461 
462 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
464  IWorkloadFactory& workloadFactory,
465  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
466  const armnn::ITensorHandleFactory& tensorHandleFactory,
467  const TensorInfo& outputTensorInfo,
468  unsigned int dimension,
469  const float qScale,
470  const int32_t qOffset)
471 {
472  TensorInfo inputTensorInfo({ 2, 3 }, ArmnnType, qScale, qOffset);
473 
474  auto input0 = QuantizedVector<T>(
475  {
476  // Batch 0
477  1.0f, 2.0f, 3.0f,
478 
479  // Batch 1
480  10.0f, 11.0f, 12.0f,
481  },
482  qScale, qOffset);
483 
484  auto input1 = QuantizedVector<T>(
485  {
486  // Batch 0
487  4.0f, 5.0f, 6.0f,
488 
489  // Batch 1
490  13.0f, 14.0f, 15.0f,
491  },
492  qScale, qOffset);
493 
494  auto input2 = QuantizedVector<T>(
495  {
496  // Batch 0
497  7.0f, 8.0f, 9.0f,
498 
499  // Batch 1
500  16.0f, 17.0f, 18.0f,
501  },
502  qScale, qOffset);
503 
504  LayerTestResult<T, 2> result(outputTensorInfo);
505 
506  std::vector<T> output;
507  output.resize(outputTensorInfo.GetNumElements());
508  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
509  { inputTensorInfo, inputTensorInfo, inputTensorInfo },
510  { input0.data(), input1.data(), input2.data() },
511  outputTensorInfo,
512  output.data(),
513  dimension,
514  true);
515 
516  result.m_ActualData = output;
517  return result;
518 }
519 
520 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
522  IWorkloadFactory& workloadFactory,
523  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
524  const armnn::ITensorHandleFactory& tensorHandleFactory,
525  float qScale,
526  int32_t qOffset)
527 {
528  TensorInfo outputTensorInfo({ 6, 3 }, ArmnnType, qScale, qOffset);
529 
530  LayerTestResult<T, 2> result = Concat2dTestImpl<ArmnnType>(
531  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 0, qScale, qOffset);
532 
533  result.m_ExpectedData = QuantizedVector<T>(
534  {
535  // Batch 0
536  1.0f, 2.0f, 3.0f,
537 
538  // Batch 1
539  10.0f, 11.0f, 12.0f,
540 
541  // Batch 2
542  4.0f, 5.0f, 6.0f,
543 
544  // Batch 3
545  13.0f, 14.0f, 15.0f,
546 
547  // Batch 4
548  7.0f, 8.0f, 9.0f,
549 
550  // Batch 5
551  16.0f, 17.0f, 18.0f,
552  },
553  qScale, qOffset);
554 
555  return result;
556 }
557 
558 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
560  IWorkloadFactory& workloadFactory,
561  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
562  const armnn::ITensorHandleFactory& tensorHandleFactory,
563  float qScale,
564  int32_t qOffset)
565 {
566  TensorInfo outputTensorInfo({ 2, 9 }, ArmnnType, qScale, qOffset);
567 
568  LayerTestResult<T, 2> result = Concat2dTestImpl<ArmnnType>(
569  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 1, qScale, qOffset);
570 
571  result.m_ExpectedData = QuantizedVector<T>(
572  {
573  // Batch 0
574  1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
575 
576  // Batch 1
577  10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f
578  },
579  qScale, qOffset);
580 
581  return result;
582 }
583 
584 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
586  IWorkloadFactory& workloadFactory,
587  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
588  const armnn::ITensorHandleFactory& tensorHandleFactory,
589  float qScale,
590  int32_t qOffset)
591 {
592  TensorInfo input0TensorInfo({ 2, 3 }, ArmnnType, qScale, qOffset);
593  auto input0 = QuantizedVector<T>(
594  {
595  // Batch 0
596  1.0f, 2.0f, 3.0f,
597 
598  // Batch 1
599  10.0f, 11.0f, 12.0f,
600  },
601  qScale, qOffset);
602 
603  TensorInfo input1TensorInfo({ 3, 3 }, ArmnnType, qScale, qOffset);
604  auto input1 = QuantizedVector<T>(
605  {
606  // Batch 0
607  4.0f, 5.0f, 6.0f,
608 
609  // Batch 1
610  13.0f, 14.0f, 15.0f,
611 
612  // Batch 0
613  7.0f, 8.0f, 9.0f,
614  },
615  qScale, qOffset);
616 
617  TensorInfo input2TensorInfo({ 1, 3 }, ArmnnType, qScale, qOffset);
618  auto input2 = QuantizedVector<T>(
619  {
620  // Batch 1
621  16.0f, 17.0f, 18.0f,
622  },
623  qScale, qOffset);
624 
625  TensorInfo outputTensorInfo({ 6, 3 }, ArmnnType, qScale, qOffset);
626  LayerTestResult<T, 2> result(outputTensorInfo);
627 
628  std::vector<T> output;
629  output.resize(outputTensorInfo.GetNumElements());
630  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
631  { input0TensorInfo, input1TensorInfo, input2TensorInfo },
632  { input0.data(), input1.data(), input2.data() },
633  outputTensorInfo,
634  output.data(),
635  0,
636  true);
637 
638  result.m_ActualData = output;
639  result.m_ExpectedData = QuantizedVector<T>(
640  {
641  // Batch 0
642  1.0f, 2.0f, 3.0f,
643 
644  // Batch 1
645  10.0f, 11.0f, 12.0f,
646 
647  // Batch 2
648  4.0f, 5.0f, 6.0f,
649 
650  // Batch 3
651  13.0f, 14.0f, 15.0f,
652 
653  // Batch 4
654  7.0f, 8.0f, 9.0f,
655 
656  // Batch 5
657  16.0f, 17.0f, 18.0f,
658  },
659  qScale, qOffset);
660 
661  return result;
662 }
663 
664 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
666  IWorkloadFactory& workloadFactory,
667  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
668  const armnn::ITensorHandleFactory& tensorHandleFactory,
669  float qScale,
670  int32_t qOffset)
671 {
672  TensorInfo input0TensorInfo({ 2, 3 }, ArmnnType, qScale, qOffset);
673  auto input0 = QuantizedVector<T>(
674  {
675  // Batch 0
676  1.0f, 2.0f, 3.0f,
677 
678  // Batch 1
679  10.0f, 11.0f, 12.0f,
680  },
681  qScale, qOffset);
682 
683  TensorInfo input1TensorInfo({ 2, 5 }, ArmnnType, qScale, qOffset);
684  auto input1 = QuantizedVector<T>(
685  {
686  // Batch 0
687  4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
688 
689  // Batch 1
690  13.0f, 14.0f, 15.0f, 16.0f, 17.0f,
691  },
692  qScale, qOffset);
693 
694  TensorInfo input2TensorInfo({ 2, 1 }, ArmnnType, qScale, qOffset);
695  auto input2 = QuantizedVector<T>(
696  {
697  // Batch 0
698  9.0f,
699 
700  // Batch 1
701  18.0f
702  },
703  qScale, qOffset);
704 
705  TensorInfo outputTensorInfo({ 2, 9 }, ArmnnType, qScale, qOffset);
706  LayerTestResult<T, 2> result(outputTensorInfo);
707 
708  std::vector<T> output;
709  output.resize(outputTensorInfo.GetNumElements());
710  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
711  { input0TensorInfo, input1TensorInfo, input2TensorInfo },
712  { input0.data(), input1.data(), input2.data() },
713  outputTensorInfo,
714  output.data(),
715  1,
716  true);
717 
718  result.m_ActualData = output;
719  result.m_ExpectedData = QuantizedVector<T>(
720  {
721  // Batch 0
722  1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
723 
724  // Batch 1
725  10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f,
726  },
727  qScale, qOffset);
728 
729  return result;
730 }
731 
732 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
734  IWorkloadFactory& workloadFactory,
735  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
736  const armnn::ITensorHandleFactory& tensorHandleFactory,
737  const TensorInfo& outputTensorInfo,
738  unsigned int dimension,
739  bool useSubtensor,
740  float qScale,
741  int32_t qOffset)
742 {
743  TensorInfo inputTensorInfo({ 2, 3, 2 }, ArmnnType, qScale, qOffset);
744 
745  auto input0 = QuantizedVector<T>(
746  {
747  // Batch 0, Channel 0
748  1.0f, 2.0f,
749 
750  // Batch 0, Channel 1
751  3.0f, 4.0f,
752 
753  // Batch 0, Channel 2
754  5.0f, 6.0f,
755 
756  // Batch 1, Channel 0
757  19.0f, 20.0f,
758 
759  // Batch 1, Channel 1
760  21.0f, 22.0f,
761 
762  // Batch 1, Channel 2
763  23.0f, 24.0f
764  },
765  qScale, qOffset);
766 
767  auto input1 = QuantizedVector<T>(
768  {
769  // Batch 0, Channel 0
770  7.0f, 8.0f,
771 
772  // Batch 0, Channel 1
773  9.0f, 10.0f,
774 
775  // Batch 0, Channel 2
776  11.0f, 12.0f,
777 
778  // Batch 1, Channel 0
779  25.0f, 26.0f,
780 
781  // Batch 1, Channel 1
782  27.0f, 28.0f,
783 
784  // Batch 1, Channel 2
785  29.0f, 30.0f
786  },
787  qScale, qOffset);
788 
789  auto input2 = QuantizedVector<T>(
790  {
791  // Batch 0, Channel 0
792  13.0f, 14.0f,
793 
794  // Batch 0, Channel 1
795  15.0f, 16.0f,
796 
797  // Batch 0, Channel 2
798  17.0f, 18.0f,
799 
800  // Batch 1, Channel 0
801  31.0f, 32.0f,
802 
803  // Batch 1, Channel 1
804  33.0f, 34.0f,
805 
806  // Batch 1, Channel 2
807  35.0f, 36.0f
808  },
809  qScale, qOffset);
810 
811  LayerTestResult<T, 3> result(outputTensorInfo);
812 
813  std::vector<T> output;
814  output.resize(outputTensorInfo.GetNumElements());
815  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
816  { inputTensorInfo, inputTensorInfo, inputTensorInfo },
817  { input0.data(), input1.data(), input2.data() },
818  outputTensorInfo,
819  output.data(),
820  dimension,
821  useSubtensor);
822 
823  result.m_ActualData = output;
824  return result;
825 }
826 
827 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
829  IWorkloadFactory& workloadFactory,
830  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
831  const armnn::ITensorHandleFactory& tensorHandleFactory,
832  float qScale,
833  int32_t qOffset)
834 {
835  TensorInfo outputTensorInfo({ 6, 3, 2 }, ArmnnType, qScale, qOffset);
836 
837  LayerTestResult<T, 3> result = Concat3dTestImpl<ArmnnType>(
838  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 0, true, qScale, qOffset);
839 
840  result.m_ExpectedData = QuantizedVector<T>(
841  {
842  // Batch 0, Channel 0
843  1.0f, 2.0f,
844 
845  // Batch 0, Channel 1
846  3.0f, 4.0f,
847 
848  // Batch 0, Channel 2
849  5.0f, 6.0f,
850 
851  // Batch 1, Channel 0
852  19.0f, 20.0f,
853 
854  // Batch 1, Channel 1
855  21.0f, 22.0f,
856 
857  // Batch 1, Channel 2
858  23.0f, 24.0f,
859 
860  // Batch 2, Channel 0
861  7.0f, 8.0f,
862 
863  // Batch 2, Channel 1
864  9.0f, 10.0f,
865 
866  // Batch 2, Channel 2
867  11.0f, 12.0f,
868 
869  // Batch 3, Channel 0
870  25.0f, 26.0f,
871 
872  // Batch 3, Channel 1
873  27.0f, 28.0f,
874 
875  // Batch 3, Channel 2
876  29.0f, 30.0f,
877 
878  // Batch 4, Channel 0
879  13.0f, 14.0f,
880 
881  // Batch 4, Channel 1
882  15.0f, 16.0f,
883 
884  // Batch 4, Channel 2
885  17.0f, 18.0f,
886 
887  // Batch 5, Channel 0
888  31.0f, 32.0f,
889 
890  // Batch 5, Channel 1
891  33.0f, 34.0f,
892 
893  // Batch 5, Channel 2
894  35.0f, 36.0f
895  },
896  qScale, qOffset);
897 
898  return result;
899 }
900 
901 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
903  IWorkloadFactory& workloadFactory,
904  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
905  const armnn::ITensorHandleFactory& tensorHandleFactory,
906  float qScale,
907  int32_t qOffset)
908 {
909  TensorInfo outputTensorInfo({ 2, 9, 2 }, ArmnnType, qScale, qOffset);
910 
911  LayerTestResult<T, 3> result = Concat3dTestImpl<ArmnnType>(
912  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 1, true, qScale, qOffset);
913 
914  result.m_ExpectedData = QuantizedVector<T>(
915  {
916  // Batch 0, Channel 0
917  1.0f, 2.0f,
918 
919  // Batch 0, Channel 1
920  3.0f, 4.0f,
921 
922  // Batch 0, Channel 2
923  5.0f, 6.0f,
924 
925  // Batch 0, Channel 3
926  7.0f, 8.0f,
927 
928  // Batch 0, Channel 4
929  9.0f, 10.0f,
930 
931  // Batch 0, Channel 5
932  11.0f, 12.0f,
933 
934  // Batch 0, Channel 6
935  13.0f, 14.0f,
936 
937  // Batch 0, Channel 7
938  15.0f, 16.0f,
939 
940  // Batch 0, Channel 8
941  17.0f, 18.0f,
942 
943  // Batch 1, Channel 0
944  19.0f, 20.0f,
945 
946  // Batch 1, Channel 1
947  21.0f, 22.0f,
948 
949  // Batch 1, Channel 2
950  23.0f, 24.0f,
951 
952  // Batch 1, Channel 3
953  25.0f, 26.0f,
954 
955  // Batch 1, Channel 4
956  27.0f, 28.0f,
957 
958  // Batch 1, Channel 5
959  29.0f, 30.0f,
960 
961  // Batch 1, Channel 6
962  31.0f, 32.0f,
963 
964  // Batch 1, Channel 7
965  33.0f, 34.0f,
966 
967  // Batch 1, Channel 8
968  35.0f, 36.0f
969  },
970  qScale, qOffset);
971 
972  return result;
973 }
974 
975 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
977  IWorkloadFactory& workloadFactory,
978  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
979  const armnn::ITensorHandleFactory& tensorHandleFactory,
980  bool useSubtensor,
981  float qScale,
982  int32_t qOffset)
983 {
984  TensorInfo outputTensorInfo({ 2, 3, 6 }, ArmnnType, qScale, qOffset);
985 
986  LayerTestResult<T, 3> result = Concat3dTestImpl<ArmnnType>(
987  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 2, useSubtensor, qScale, qOffset);
988 
989  result.m_ExpectedData = QuantizedVector<T>(
990  {
991  // Batch 0, Channel 0
992  1.0f, 2.0f, 7.0f, 8.0f, 13.0f, 14.0f,
993 
994  // Batch 0, Channel 1
995  3.0f, 4.0f, 9.0f, 10.0f, 15.0f, 16.0f,
996 
997  // Batch 0, Channel 2
998  5.0f, 6.0f, 11.0f, 12.0f, 17.0f, 18.0f,
999 
1000  // Batch 1, Channel 0
1001  19.0f, 20.0f, 25.0f, 26.0f, 31.0f, 32.0f,
1002 
1003  // Batch 1, Channel 1
1004  21.0f, 22.0f, 27.0f, 28.0f, 33.0f, 34.0f,
1005 
1006  // Batch 1, Channel 2
1007  23.0f, 24.0f, 29.0f, 30.0f, 35.0f, 36.0f,
1008  },
1009  qScale, qOffset);
1010 
1011  return result;
1012 }
1013 
1014 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1016  IWorkloadFactory& workloadFactory,
1017  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1018  const armnn::ITensorHandleFactory& tensorHandleFactory,
1019  float qScale,
1020  int32_t qOffset)
1021 {
1022  TensorInfo input0TensorInfo({ 2, 3, 2 }, ArmnnType);
1023  auto input0 = QuantizedVector<T>(
1024  {
1025  // Batch 0, Channel 0
1026  1.0f, 2.0f,
1027 
1028  // Batch 0, Channel 1
1029  3.0f, 4.0f,
1030 
1031  // Batch 0, Channel 2
1032  5.0f, 6.0f,
1033 
1034  // Batch 1, Channel 0
1035  19.0f, 20.0f,
1036 
1037  // Batch 1, Channel 1
1038  21.0f, 22.0f,
1039 
1040  // Batch 1, Channel 2
1041  23.0f, 24.0f
1042  },
1043  qScale, qOffset);
1044 
1045  TensorInfo input1TensorInfo({ 1, 3, 2 }, ArmnnType);
1046  auto input1 = QuantizedVector<T>(
1047  {
1048  // Batch 0, Channel 0
1049  7.0f, 8.0f,
1050 
1051  // Batch 0, Channel 1
1052  9.0f, 10.0f,
1053 
1054  // Batch 0, Channel 2
1055  11.0f, 12.0f,
1056  },
1057  qScale, qOffset);
1058 
1059  TensorInfo input2TensorInfo({ 3, 3, 2 }, ArmnnType);
1060  auto input2 = QuantizedVector<T>(
1061  {
1062  // Batch 0, Channel 0
1063  25.0f, 26.0f,
1064 
1065  // Batch 0, Channel 1
1066  27.0f, 28.0f,
1067 
1068  // Batch 0, Channel 2
1069  29.0f, 30.0f,
1070 
1071  // Batch 1, Channel 0
1072  13.0f, 14.0f,
1073 
1074  // Batch 1, Channel 1
1075  15.0f, 16.0f,
1076 
1077  // Batch 1, Channel 2
1078  17.0f, 18.0f,
1079 
1080  // Batch 2, Channel 0
1081  31.0f, 32.0f,
1082 
1083  // Batch 2, Channel 1
1084  33.0f, 34.0f,
1085 
1086  // Batch 2, Channel 2
1087  35.0f, 36.0f
1088  },
1089  qScale, qOffset);
1090 
1091  TensorInfo outputTensorInfo({ 6, 3, 2 }, ArmnnType);
1092  LayerTestResult<T, 3> result(outputTensorInfo);
1093 
1094  std::vector<T> output;
1095  output.resize(outputTensorInfo.GetNumElements());
1096  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
1097  { input0TensorInfo, input1TensorInfo, input2TensorInfo },
1098  { input0.data(), input1.data(), input2.data() },
1099  outputTensorInfo,
1100  output.data(),
1101  0,
1102  true);
1103 
1104  result.m_ActualData = output;
1105  result.m_ExpectedData = QuantizedVector<T>(
1106  {
1107  // Batch 0, Channel 0
1108  1.0f, 2.0f,
1109 
1110  // Batch 0, Channel 1
1111  3.0f, 4.0f,
1112 
1113  // Batch 0, Channel 2
1114  5.0f, 6.0f,
1115 
1116  // Batch 1, Channel 0
1117  19.0f, 20.0f,
1118 
1119  // Batch 1, Channel 1
1120  21.0f, 22.0f,
1121 
1122  // Batch 1, Channel 2
1123  23.0f, 24.0f,
1124 
1125  // Batch 2, Channel 0
1126  7.0f, 8.0f,
1127 
1128  // Batch 2, Channel 1
1129  9.0f, 10.0f,
1130 
1131  // Batch 2, Channel 2
1132  11.0f, 12.0f,
1133 
1134  // Batch 3, Channel 0
1135  25.0f, 26.0f,
1136 
1137  // Batch 3, Channel 1
1138  27.0f, 28.0f,
1139 
1140  // Batch 3, Channel 2
1141  29.0f, 30.0f,
1142 
1143  // Batch 4, Channel 0
1144  13.0f, 14.0f,
1145 
1146  // Batch 4, Channel 1
1147  15.0f, 16.0f,
1148 
1149  // Batch 4, Channel 2
1150  17.0f, 18.0f,
1151 
1152  // Batch 5, Channel 0
1153  31.0f, 32.0f,
1154 
1155  // Batch 5, Channel 1
1156  33.0f, 34.0f,
1157 
1158  // Batch 5, Channel 2
1159  35.0f, 36.0f
1160  },
1161  qScale, qOffset);
1162 
1163  return result;
1164 }
1165 
1166 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1168  IWorkloadFactory& workloadFactory,
1169  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1170  const armnn::ITensorHandleFactory& tensorHandleFactory,
1171  float qScale,
1172  int32_t qOffset)
1173 {
1174  TensorInfo input0TensorInfo({ 2, 3, 2 }, ArmnnType, qScale, qOffset);
1175  auto input0 = QuantizedVector<T>(
1176  {
1177  // Batch 0, Channel 0
1178  1.0f, 2.0f,
1179 
1180  // Batch 0, Channel 1
1181  3.0f, 4.0f,
1182 
1183  // Batch 0, Channel 2
1184  5.0f, 6.0f,
1185 
1186  // Batch 1, Channel 0
1187  19.0f, 20.0f,
1188 
1189  // Batch 1, Channel 1
1190  21.0f, 22.0f,
1191 
1192  // Batch 1, Channel 2
1193  23.0f, 24.0f
1194  },
1195  qScale, qOffset);
1196 
1197  TensorInfo input1TensorInfo({ 2, 4, 2 }, ArmnnType, qScale, qOffset);
1198  auto input1 = QuantizedVector<T>(
1199  {
1200  // Batch 0, Channel 0
1201  7.0f, 8.0f,
1202 
1203  // Batch 0, Channel 1
1204  9.0f, 10.0f,
1205 
1206  // Batch 0, Channel 2
1207  11.0f, 12.0f,
1208 
1209  // Batch 0, Channel 3
1210  25.0f, 26.0f,
1211 
1212  // Batch 1, Channel 0
1213  27.0f, 28.0f,
1214 
1215  // Batch 1, Channel 1
1216  29.0f, 30.0f,
1217 
1218  // Batch 1, Channel 2
1219  13.0f, 14.0f,
1220 
1221  // Batch 1, Channel 3
1222  15.0f, 16.0f,
1223  },
1224  qScale, qOffset);
1225 
1226  TensorInfo input2TensorInfo({ 2, 1, 2 }, ArmnnType, qScale, qOffset);
1227  auto input2 = QuantizedVector<T>(
1228  {
1229  // Batch 0, Channel 0
1230  17.0f, 18.0f,
1231 
1232  // Batch 1, Channel 0
1233  31.0f, 32.0f,
1234  },
1235  qScale, qOffset);
1236 
1237  TensorInfo outputTensorInfo({ 2, 8, 2 }, ArmnnType, qScale, qOffset);
1238  LayerTestResult<T, 3> result(outputTensorInfo);
1239 
1240  std::vector<T> output;
1241  output.resize(outputTensorInfo.GetNumElements());
1242  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
1243  { input0TensorInfo, input1TensorInfo, input2TensorInfo },
1244  { input0.data(), input1.data(), input2.data() },
1245  outputTensorInfo,
1246  output.data(),
1247  1,
1248  true);
1249 
1250  result.m_ActualData = output;
1251  result.m_ExpectedData = QuantizedVector<T>(
1252  {
1253  // Batch 0, Channel 0
1254  1.0f, 2.0f,
1255 
1256  // Batch 0, Channel 1
1257  3.0f, 4.0f,
1258 
1259  // Batch 0, Channel 2
1260  5.0f, 6.0f,
1261 
1262  // Batch 0, Channel 3
1263  7.0f, 8.0f,
1264 
1265  // Batch 0, Channel 4
1266  9.0f, 10.0f,
1267 
1268  // Batch 0, Channel 5
1269  11.0f, 12.0f,
1270 
1271  // Batch 0, Channel 6
1272  25.0f, 26.0f,
1273 
1274  // Batch 0, Channel 7
1275  17.0f, 18.0f,
1276 
1277  // Batch 1, Channel 0
1278  19.0f, 20.0f,
1279 
1280  // Batch 1, Channel 1
1281  21.0f, 22.0f,
1282 
1283  // Batch 1, Channel 2
1284  23.0f, 24.0f,
1285 
1286  // Batch 1, Channel 3
1287  27.0f, 28.0f,
1288 
1289  // Batch 1, Channel 4
1290  29.0f, 30.0f,
1291 
1292  // Batch 1, Channel 5
1293  13.0f, 14.0f,
1294 
1295  // Batch 1, Channel 6
1296  15.0f, 16.0f,
1297 
1298  // Batch 1, Channel 7
1299  31.0f, 32.0f,
1300  },
1301  qScale, qOffset);
1302 
1303  return result;
1304 }
1305 
1306 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1308  IWorkloadFactory& workloadFactory,
1309  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1310  const armnn::ITensorHandleFactory& tensorHandleFactory,
1311  bool useSubtensor,
1312  float qScale,
1313  int32_t qOffset)
1314 {
1315  TensorInfo input0TensorInfo({ 2, 3, 2 }, ArmnnType, qScale, qOffset);
1316  auto input0 = QuantizedVector<T>(
1317  {
1318  // Batch 0, Channel 0
1319  1.0f, 2.0f,
1320 
1321  // Batch 0, Channel 1
1322  3.0f, 4.0f,
1323 
1324  // Batch 0, Channel 2
1325  5.0f, 6.0f,
1326 
1327  // Batch 1, Channel 0
1328  19.0f, 20.0f,
1329 
1330  // Batch 1, Channel 1
1331  21.0f, 22.0f,
1332 
1333  // Batch 1, Channel 2
1334  23.0f, 24.0f
1335  },
1336  qScale, qOffset);
1337 
1338  TensorInfo input1TensorInfo({ 2, 3, 1 }, ArmnnType, qScale, qOffset);
1339  auto input1 = QuantizedVector<T>(
1340  {
1341  // Batch 0, Channel 0
1342  7.0f,
1343 
1344  // Batch 0, Channel 1
1345  9.0f,
1346 
1347  // Batch 0, Channel 2
1348  11.0f,
1349 
1350  // Batch 1, Channel 0
1351  25.0f,
1352 
1353  // Batch 1, Channel 1
1354  27.0f,
1355 
1356  // Batch 1, Channel 2
1357  29.0f
1358  },
1359  qScale, qOffset);
1360 
1361  TensorInfo input2TensorInfo({ 2, 3, 3 }, ArmnnType, qScale, qOffset);
1362  auto input2 = QuantizedVector<T>(
1363  {
1364  // Batch 0, Channel 0
1365  13.0f, 14.0f, 50.0f,
1366 
1367  // Batch 0, Channel 1
1368  15.0f, 16.0f, 51.0f,
1369 
1370  // Batch 0, Channel 2
1371  17.0f, 18.0f, 52.0f,
1372 
1373  // Batch 1, Channel 0
1374  31.0f, 32.0f, 53.0f,
1375 
1376  // Batch 1, Channel 1
1377  33.0f, 34.0f, 54.0f,
1378 
1379  // Batch 1, Channel 2
1380  35.0f, 36.0f, 55.0f,
1381  },
1382  qScale, qOffset);
1383 
1384  TensorInfo outputTensorInfo({ 2, 3, 6 }, ArmnnType, qScale, qOffset);
1385  LayerTestResult<T, 3> result(outputTensorInfo);
1386 
1387  std::vector<T> output;
1388  output.resize(outputTensorInfo.GetNumElements());
1389  Concatenate<T>(workloadFactory, memoryManager, tensorHandleFactory,
1390  { input0TensorInfo, input1TensorInfo, input2TensorInfo },
1391  { input0.data(), input1.data(), input2.data() },
1392  outputTensorInfo,
1393  output.data(),
1394  2,
1395  useSubtensor);
1396 
1397  result.m_ActualData = output;
1398  result.m_ExpectedData = QuantizedVector<T>(
1399  {
1400  // Batch 0, Channel 0
1401  1.0f, 2.0f, 7.0f, 13.0f, 14.0f, 50.0f,
1402 
1403  // Batch 0, Channel 1
1404  3.0f, 4.0f, 9.0f, 15.0f, 16.0f, 51.0f,
1405 
1406  // Batch 0, Channel 2
1407  5.0f, 6.0f, 11.0f, 17.0f, 18.0f, 52.0f,
1408 
1409  // Batch 1, Channel 0
1410  19.0f, 20.0f, 25.0f, 31.0f, 32.0f, 53.0f,
1411 
1412  // Batch 1, Channel 1
1413  21.0f, 22.0f, 27.0f, 33.0f, 34.0f, 54.0f,
1414 
1415  // Batch 1, Channel 2
1416  23.0f, 24.0f, 29.0f, 35.0f, 36.0f, 55.0f,
1417  },
1418  qScale, qOffset);
1419 
1420  return result;
1421 }
1422 
1423 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1425  IWorkloadFactory& workloadFactory,
1426  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1427  const armnn::ITensorHandleFactory& tensorHandleFactory,
1428  const TensorInfo& outputTensorInfo,
1429  unsigned int dimension,
1430  bool useSubtensor,
1431  float qScale,
1432  int32_t qOffset)
1433 {
1434  TensorInfo inputTensorInfo({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1435 
1436  auto input0 = QuantizedVector<T>(
1437  {
1438  1.0f, 2.0f,
1439  3.0f, 4.0f,
1440  5.0f, 6.0f,
1441  7.0f, 8.0f,
1442  9.0f, 10.0f,
1443  11.0f, 12.0f
1444  },
1445  qScale, qOffset);
1446 
1447  auto input1 = QuantizedVector<T>(
1448  {
1449  11.0f, 12.0f,
1450  13.0f, 14.0f,
1451  15.0f, 16.0f,
1452  17.0f, 18.0f,
1453  19.0f, 20.0f,
1454  21.0f, 22.0f
1455  },
1456  qScale, qOffset);
1457 
1458  auto input2 = QuantizedVector<T>(
1459  {
1460  21.0f, 22.0f,
1461  23.0f, 24.0f,
1462  25.0f, 26.0f,
1463  27.0f, 28.0f,
1464  29.0f, 30.0f,
1465  31.0f, 32.0f
1466  },
1467  qScale, qOffset);
1468 
1469  LayerTestResult<T, 4> result(outputTensorInfo);
1470 
1471  std::vector<T> output;
1472  output.resize(outputTensorInfo.GetNumElements());
1473 
1474  Concatenate<T>(workloadFactory,
1475  memoryManager,
1476  tensorHandleFactory,
1477  {inputTensorInfo, inputTensorInfo, inputTensorInfo},
1478  {input0.data(), input1.data(), input2.data()},
1479  outputTensorInfo,
1480  output.data(),
1481  dimension,
1482  useSubtensor);
1483 
1484  result.m_ActualData = output;
1485  return result;
1486 }
1487 
1488 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1490  IWorkloadFactory& workloadFactory,
1491  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1492  const armnn::ITensorHandleFactory& tensorHandleFactory,
1493  float qScale,
1494  int32_t qOffset)
1495 {
1496  TensorInfo outputTensorInfo({ 3, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1497 
1498  LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1499  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 0, true, qScale, qOffset);
1500 
1501  result.m_ExpectedData = QuantizedVector<T>(
1502  {
1503  1.0f, 2.0f,
1504  3.0f, 4.0f,
1505  5.0f, 6.0f,
1506  7.0f, 8.0f,
1507  9.0f, 10.0f,
1508  11.0f, 12.0f,
1509 
1510  11.0f, 12.0f,
1511  13.0f, 14.0f,
1512  15.0f, 16.0f,
1513  17.0f, 18.0f,
1514  19.0f, 20.0f,
1515  21.0f, 22.0f,
1516 
1517  21.0f, 22.0f,
1518  23.0f, 24.0f,
1519  25.0f, 26.0f,
1520  27.0f, 28.0f,
1521  29.0f, 30.0f,
1522  31.0f, 32.0f
1523  },
1524  qScale, qOffset);
1525 
1526  return result;
1527 }
1528 
1529 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1531  IWorkloadFactory& workloadFactory,
1532  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1533  const armnn::ITensorHandleFactory& tensorHandleFactory,
1534  float qScale,
1535  int32_t qOffset)
1536 {
1537  TensorInfo outputTensorInfo({ 1, 9, 2, 2 }, ArmnnType, qScale, qOffset);
1538 
1539  LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1540  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 1, true, qScale, qOffset);
1541 
1542  result.m_ExpectedData = QuantizedVector<T>(
1543  {
1544  1.0f, 2.0f,
1545  3.0f, 4.0f,
1546  5.0f, 6.0f,
1547  7.0f, 8.0f,
1548  9.0f, 10.0f,
1549  11.0f, 12.0f,
1550 
1551  11.0f, 12.0f,
1552  13.0f, 14.0f,
1553  15.0f, 16.0f,
1554  17.0f, 18.0f,
1555  19.0f, 20.0f,
1556  21.0f, 22.0f,
1557 
1558  21.0f, 22.0f,
1559  23.0f, 24.0f,
1560  25.0f, 26.0f,
1561  27.0f, 28.0f,
1562  29.0f, 30.0f,
1563  31.0f, 32.0f
1564  },
1565  qScale, qOffset);
1566 
1567  return result;
1568 }
1569 
1570 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1572  IWorkloadFactory& workloadFactory,
1573  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1574  const armnn::ITensorHandleFactory& tensorHandleFactory,
1575  float qScale,
1576  int32_t qOffset)
1577 {
1578  TensorInfo outputTensorInfo({ 1, 3, 6, 2 }, ArmnnType, qScale, qOffset);
1579 
1580  LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1581  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 2, true, qScale, qOffset);
1582 
1583  result.m_ExpectedData = QuantizedVector<T>(
1584  {
1585  1.0f, 2.0f,
1586  3.0f, 4.0f,
1587  11.0f, 12.0f,
1588  13.0f, 14.0f,
1589  21.0f, 22.0f,
1590  23.0f, 24.0f,
1591 
1592  5.0f, 6.0f,
1593  7.0f, 8.0f,
1594  15.0f, 16.0f,
1595  17.0f, 18.0f,
1596  25.0f, 26.0f,
1597  27.0f, 28.0f,
1598 
1599  9.0f, 10.0f,
1600  11.0f, 12.0f,
1601  19.0f, 20.0f,
1602  21.0f, 22.0f,
1603  29.0f, 30.0f,
1604  31.0f, 32.0f
1605  },
1606  qScale, qOffset);
1607 
1608  return result;
1609 }
1610 
1611 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1613  IWorkloadFactory& workloadFactory,
1614  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1615  const armnn::ITensorHandleFactory& tensorHandleFactory,
1616  float qScale,
1617  int32_t qOffset,
1618  bool useSubtensor)
1619 {
1620  TensorInfo outputTensorInfo({ 1, 3, 2, 6 }, ArmnnType, qScale, qOffset);
1621 
1622  LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1623  workloadFactory, memoryManager, tensorHandleFactory, outputTensorInfo, 3, useSubtensor, qScale, qOffset);
1624 
1625  result.m_ExpectedData = QuantizedVector<T>(
1626  {
1627  1.0f, 2.0f,
1628  11.0f, 12.0f,
1629  21.0f, 22.0f,
1630  3.0f, 4.0f,
1631  13.0f, 14.0f,
1632  23.0f, 24.0f,
1633 
1634  5.0f, 6.0f,
1635  15.0f, 16.0f,
1636  25.0f, 26.0f,
1637  7.0f, 8.0f,
1638  17.0f, 18.0f,
1639  27.0f, 28.0f,
1640 
1641  9.0f, 10.0f,
1642  19.0f, 20.0f,
1643  29.0f, 30.0f,
1644  11.0f, 12.0f,
1645  21.0f, 22.0f,
1646  31.0f, 32.0f
1647  },
1648  qScale, qOffset);
1649 
1650  return result;
1651 }
1652 
1653 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1655  IWorkloadFactory& workloadFactory,
1656  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1657  const armnn::ITensorHandleFactory& tensorHandleFactory,
1658  float qScale,
1659  int32_t qOffset)
1660 {
1661  constexpr unsigned int dimension = 0u;
1662 
1663  TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1664  auto input0 = QuantizedVector<T>(
1665  {
1666  1.0f, 2.0f,
1667  3.0f, 4.0f,
1668  5.0f, 6.0f,
1669  7.0f, 8.0f,
1670  9.0f, 10.0f,
1671  11.0f, 12.0f
1672  },
1673  qScale, qOffset);
1674 
1675  TensorInfo inputTensorInfo1({ 2, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1676 
1677  auto input1 = QuantizedVector<T>(
1678  {
1679  11.0f, 12.0f,
1680  13.0f, 14.0f,
1681  15.0f, 16.0f,
1682  17.0f, 18.0f,
1683  19.0f, 20.0f,
1684  21.0f, 22.0f,
1685 
1686  21.0f, 22.0f,
1687  23.0f, 24.0f,
1688  25.0f, 26.0f,
1689  27.0f, 28.0f,
1690  29.0f, 30.0f,
1691  31.0f, 32.0f
1692  },
1693  qScale, qOffset);
1694 
1695  TensorInfo outputTensorInfo({ 3, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1696 
1697  LayerTestResult<T, 4> result(outputTensorInfo);
1698 
1699  std::vector<T> output;
1700  output.resize(outputTensorInfo.GetNumElements());
1701  Concatenate<T>(workloadFactory,
1702  memoryManager,
1703  tensorHandleFactory,
1704  {inputTensorInfo0, inputTensorInfo1},
1705  {input0.data(), input1.data()},
1706  outputTensorInfo,
1707  output.data(),
1708  dimension,
1709  true);
1710 
1711  result.m_ActualData = output;
1712  result.m_ExpectedData = QuantizedVector<T>(
1713  {
1714  1.0f, 2.0f,
1715  3.0f, 4.0f,
1716  5.0f, 6.0f,
1717  7.0f, 8.0f,
1718  9.0f, 10.0f,
1719  11.0f, 12.0f,
1720 
1721  11.0f, 12.0f,
1722  13.0f, 14.0f,
1723  15.0f, 16.0f,
1724  17.0f, 18.0f,
1725  19.0f, 20.0f,
1726  21.0f, 22.0f,
1727 
1728  21.0f, 22.0f,
1729  23.0f, 24.0f,
1730  25.0f, 26.0f,
1731  27.0f, 28.0f,
1732  29.0f, 30.0f,
1733  31.0f, 32.0f
1734  },
1735  qScale, qOffset);
1736 
1737  return result;
1738 }
1739 
1740 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1742  IWorkloadFactory& workloadFactory,
1743  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1744  const armnn::ITensorHandleFactory& tensorHandleFactory,
1745  float qScale,
1746  int32_t qOffset)
1747 {
1748  constexpr unsigned int dimension = 1u;
1749 
1750  TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1751  auto input0 = QuantizedVector<T>(
1752  {
1753  1.0f, 2.0f,
1754  3.0f, 4.0f,
1755  5.0f, 6.0f,
1756  7.0f, 8.0f,
1757  9.0f, 10.0f,
1758  11.0f, 12.0f
1759  },
1760  qScale, qOffset);
1761 
1762  TensorInfo inputTensorInfo1({ 1, 2, 2, 2 }, ArmnnType, qScale, qOffset);
1763 
1764  auto input1 = QuantizedVector<T>(
1765  {
1766  11.0f, 12.0f,
1767  13.0f, 14.0f,
1768  15.0f, 16.0f,
1769  17.0f, 18.0f,
1770  },
1771  qScale, qOffset);
1772 
1773  TensorInfo outputTensorInfo({ 1, 5, 2, 2 }, ArmnnType, qScale, qOffset);
1774 
1775  LayerTestResult<T, 4> result(outputTensorInfo);
1776 
1777  std::vector<T> output;
1778  output.resize(outputTensorInfo.GetNumElements());
1779  Concatenate<T>(workloadFactory,
1780  memoryManager,
1781  tensorHandleFactory,
1782  {inputTensorInfo0, inputTensorInfo1},
1783  {input0.data(), input1.data()},
1784  outputTensorInfo,
1785  output.data(),
1786  dimension,
1787  true);
1788 
1789  result.m_ActualData = output;
1790  result.m_ExpectedData = QuantizedVector<T>(
1791  {
1792  1.0f, 2.0f,
1793  3.0f, 4.0f,
1794  5.0f, 6.0f,
1795  7.0f, 8.0f,
1796  9.0f, 10.0f,
1797  11.0f, 12.0f,
1798  11.0f, 12.0f,
1799  13.0f, 14.0f,
1800  15.0f, 16.0f,
1801  17.0f, 18.0f
1802  },
1803  qScale, qOffset);
1804 
1805  return result;
1806 }
1807 
1808 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1810  IWorkloadFactory& workloadFactory,
1811  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1812  const armnn::ITensorHandleFactory& tensorHandleFactory,
1813  float qScale,
1814  int32_t qOffset)
1815 {
1816  constexpr unsigned int dimension = 2u;
1817 
1818  TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1819  auto input0 = QuantizedVector<T>(
1820  {
1821  1.0f, 2.0f,
1822  3.0f, 4.0f,
1823  5.0f, 6.0f,
1824  7.0f, 8.0f,
1825  9.0f, 10.0f,
1826  11.0f, 12.0f
1827  },
1828  qScale, qOffset);
1829 
1830  TensorInfo inputTensorInfo1({ 1, 3, 3, 2 }, ArmnnType, qScale, qOffset);
1831  auto input1 = QuantizedVector<T>(
1832  {
1833  11.0f, 12.0f,
1834  13.0f, 14.0f,
1835  15.0f, 16.0f,
1836  17.0f, 18.0f,
1837  19.0f, 20.0f,
1838  21.0f, 22.0f,
1839  23.0f, 24.0f,
1840  25.0f, 26.0f,
1841  27.0f, 28.0f
1842  },
1843  qScale, qOffset);
1844 
1845  TensorInfo outputTensorInfo({ 1, 3, 5, 2 }, ArmnnType, qScale, qOffset);
1846  LayerTestResult<T, 4> result(outputTensorInfo);
1847 
1848  std::vector<T> output;
1849  output.resize(outputTensorInfo.GetNumElements());
1850  Concatenate<T>(workloadFactory,
1851  memoryManager,
1852  tensorHandleFactory,
1853  {inputTensorInfo0, inputTensorInfo1},
1854  {input0.data(), input1.data()},
1855  outputTensorInfo,
1856  output.data(),
1857  dimension,
1858  true);
1859 
1860  result.m_ActualData = output;
1861  result.m_ExpectedData = QuantizedVector<T>(
1862  {
1863  1.0f, 2.0f,
1864  3.0f, 4.0f,
1865  11.0f, 12.0f,
1866  13.0f, 14.0f,
1867  15.0f, 16.0f,
1868 
1869  5.0f, 6.0f,
1870  7.0f, 8.0f,
1871  17.0f, 18.0f,
1872  19.0f, 20.0f,
1873  21.0f, 22.0f,
1874 
1875  9.0f, 10.0f,
1876  11.0f, 12.0f,
1877  23.0f, 24.0f,
1878  25.0f, 26.0f,
1879  27.0f, 28.0f
1880  },
1881  qScale, qOffset);
1882 
1883  return result;
1884 }
1885 
1886 template<DataType ArmnnType, typename T = ResolveType<ArmnnType>>
1888  IWorkloadFactory& workloadFactory,
1889  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1890  const armnn::ITensorHandleFactory& tensorHandleFactory,
1891  float qScale,
1892  int32_t qOffset,
1893  bool useSubtensor)
1894 {
1895  constexpr unsigned int dimension = 3u;
1896 
1897  TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1898  auto input0 = QuantizedVector<T>(
1899  {
1900  1.0f, 2.0f,
1901  3.0f, 4.0f,
1902  5.0f, 6.0f,
1903  7.0f, 8.0f,
1904  9.0f, 10.0f,
1905  11.0f, 12.0f
1906  },
1907  qScale, qOffset);
1908 
1909  TensorInfo inputTensorInfo1({ 1, 3, 2, 3 }, ArmnnType, qScale, qOffset);
1910  auto input1 = QuantizedVector<T>(
1911  {
1912  11.0f, 12.0f, 13.0f,
1913  14.0f, 15.0f, 16.0f,
1914 
1915  17.0f, 18.0f, 19.0f,
1916  20.0f, 21.0f, 22.0f,
1917 
1918  23.0f, 24.0f, 25.0f,
1919  26.0f, 27.0f, 28.0f
1920  },
1921  qScale, qOffset);
1922 
1923  TensorInfo outputTensorInfo({ 1, 3, 2, 5 }, ArmnnType, qScale, qOffset);
1924 
1925  LayerTestResult<T, 4> result(outputTensorInfo);
1926 
1927  std::vector<T> output;
1928  output.resize(outputTensorInfo.GetNumElements());
1929  Concatenate<T>(workloadFactory,
1930  memoryManager,
1931  tensorHandleFactory,
1932  {inputTensorInfo0, inputTensorInfo1},
1933  {input0.data(), input1.data()},
1934  outputTensorInfo,
1935  output.data(),
1936  dimension,
1937  useSubtensor);
1938 
1939  result.m_ActualData = output;
1940  result.m_ExpectedData = QuantizedVector<T>(
1941  {
1942  1.0f, 2.0f, 11.0f, 12.0f, 13.0f,
1943  3.0f, 4.0f, 14.0f, 15.0f, 16.0f,
1944  5.0f, 6.0f, 17.0f, 18.0f, 19.0f,
1945  7.0f, 8.0f, 20.0f, 21.0f, 22.0f,
1946  9.0f, 10.0f, 23.0f, 24.0f, 25.0f,
1947  11.0f, 12.0f, 26.0f, 27.0f, 28.0f
1948  },
1949  qScale, qOffset);
1950 
1951  return result;
1952 }
1953 
1954 template<DataType ArmnnType, typename T>
1956  IWorkloadFactory& workloadFactory,
1957  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1958  const armnn::ITensorHandleFactory& tensorHandleFactory,
1959  bool useSubtensor)
1960 {
1961  IgnoreUnused(memoryManager);
1962 
1963  // Defines the tensor descriptors.
1964  TensorInfo outputTensorInfo({ 3, 6, 3 }, ArmnnType);
1965  TensorInfo inputTensorInfo1({ 3, 6, 2 }, ArmnnType);
1966  TensorInfo inputTensorInfo2({ 3, 6, 1 }, ArmnnType);
1967 
1968  std::vector<TensorShape> inputTensorShapes({inputTensorInfo1.GetShape(), inputTensorInfo2.GetShape()});
1969 
1970  // Quantized input1 tensor.
1971  const float inputScale1 = 0.5f;
1972  const int32_t inputOffset1 = 5;
1973 
1974  std::vector<T> input1 =
1975  {
1976  1, 2, 3,
1977  4, 5, 6,
1978  7, 8, 9,
1979  10, 11, 12,
1980  13, 14, 15,
1981  16, 17, 18,
1982 
1983  19, 20, 21,
1984  22, 23, 24,
1985  25, 26, 27,
1986  28, 29, 30,
1987  31, 32, 33,
1988  34, 35, 36
1989  };
1990 
1991  // Quatized input2 tensor.
1992  const float inputScale2 = 0.2f;
1993  const int32_t inputOffset2 = 10;
1994 
1995  std::vector<T> input2 =
1996  {
1997  37, 38, 39,
1998  40, 41, 42,
1999  43, 44, 45,
2000  46, 47, 48,
2001  49, 50, 51,
2002  52, 53, 54
2003  };
2004 
2005  // Quantized output tensor.
2006  const float outputScale = 0.1f;
2007  const int32_t outputOffset = 20;
2008 
2009  std::vector<T> actualOutput(outputTensorInfo.GetNumElements());
2010 
2011  std::vector<T> expectedOutput =
2012  {
2013  0, 5, 74,
2014  10, 15, 76,
2015  20, 25, 78,
2016  30, 35, 80,
2017  40, 45, 82,
2018  50, 55, 84,
2019 
2020  60, 65, 86,
2021  70, 75, 88,
2022  80, 85, 90,
2023  90, 95, 92,
2024  100, 105, 94,
2025  110, 115, 96,
2026 
2027  120, 125, 98,
2028  130, 135, 100,
2029  140, 145, 102,
2030  150, 155, 104,
2031  160, 165, 106,
2032  170, 175, 108
2033  };
2034 
2035  outputTensorInfo.SetQuantizationScale(outputScale);
2036  outputTensorInfo.SetQuantizationOffset(outputOffset);
2037  inputTensorInfo1.SetQuantizationScale(inputScale1);
2038  inputTensorInfo1.SetQuantizationOffset(inputOffset1);
2039  inputTensorInfo2.SetQuantizationScale(inputScale2);
2040  inputTensorInfo2.SetQuantizationOffset(inputOffset2);
2041 
2042  std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
2043  ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2044 
2045  std::vector<unsigned int> wOrigin2 = { 0, 0, 2 }; //Extent of the window is defined by size of input[1].
2046  ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2047 
2048  std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
2049 
2050  bool subTensorsSupported = useSubtensor && workloadFactory.SupportsSubTensors();
2051 
2052  std::unique_ptr<ITensorHandle> inputHandle1 =
2053  subTensorsSupported ?
2054  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2055  tensorHandleFactory.CreateTensorHandle(inputTensorInfo1);
2056 
2057  std::unique_ptr<ITensorHandle> inputHandle2 =
2058  subTensorsSupported ?
2059  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2060  tensorHandleFactory.CreateTensorHandle(inputTensorInfo2);
2061 
2062  ConcatQueueDescriptor data;
2064  inputTensorShapes.begin(),inputTensorShapes.end(), 2);
2065  data.m_Parameters = desc;
2066 
2068  AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2069  AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2070  AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2071 
2072  data.m_ViewOrigins.push_back(window1);
2073  data.m_ViewOrigins.push_back(window2);
2074 
2075  std::unique_ptr<IWorkload> workload = workloadFactory.CreateWorkload(LayerType::Concat, data, info);
2076 
2077  inputHandle1->Allocate();
2078  inputHandle2->Allocate();
2079  outputHandle->Allocate();
2080 
2081  CopyDataToITensorHandle(inputHandle1.get(), input1.data());
2082  CopyDataToITensorHandle(inputHandle2.get(), input2.data());
2083 
2084  workload->PostAllocationConfigure();
2085  workload->Execute();
2086 
2087  CopyDataFromITensorHandle(actualOutput.data(), outputHandle.get());
2088 
2089  return LayerTestResult<T, 3>(actualOutput,
2090  expectedOutput,
2091  outputHandle->GetShape(),
2092  outputTensorInfo.GetShape());
2093 }
2094 
2095 //
2096 // Explicit template specializations
2097 //
2098 
2100 ConcatDifferentInputOutputQParamTest<DataType::QAsymmU8>(
2101  IWorkloadFactory& workloadFactory,
2102  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2103  const armnn::ITensorHandleFactory& tensorHandleFactory,
2104  bool useSubtensor);
2105 
2107 ConcatDifferentInputOutputQParamTest<DataType::QSymmS16>(
2108  IWorkloadFactory& workloadFactory,
2109  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2110  const armnn::ITensorHandleFactory& tensorHandleFactory,
2111  bool useSubtensor);
2112 
2113 //
2114 // Implementation functions
2115 //
2116 
2118  IWorkloadFactory& workloadFactory,
2119  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2120  const armnn::ITensorHandleFactory& tensorHandleFactory)
2121 {
2122  IgnoreUnused(memoryManager);
2123 
2124  unsigned int outputWidth = 3;
2125  unsigned int outputHeight = 6;
2126  unsigned int outputChannels = 3;
2127 
2128  unsigned int inputWidth1 = 3;
2129  unsigned int inputHeight1 = 6;
2130  unsigned int inputChannels1 = 2;
2131 
2132  unsigned int inputWidth2 = 3;
2133  unsigned int inputHeight2 = 6;
2134  unsigned int inputChannels2 = 1;
2135 
2136  // Define the tensor descriptors.
2137  TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, DataType::Float32);
2138  TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, DataType::Float32);
2139  TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, DataType::Float32);
2140 
2141  std::vector<float> actualOutput(outputTensorInfo.GetNumElements());
2142 
2143  std::vector<float> expectedOutput =
2144  {
2145  1.0f, 2.0f, 3.0f,
2146  4.0f, 5.0f, 6.0f,
2147  7.0f, 8.0f, 9.0f,
2148  10.0f, 11.0f, 12.0f,
2149  13.0f, 14.0f, 15.0f,
2150  16.0f, 17.0f, 18.0f,
2151 
2152  19.0f, 20.0f, 21.0f,
2153  22.0f, 23.0f, 24.0f,
2154  25.0f, 26.0f, 27.0f,
2155  28.0f, 29.0f, 30.0f,
2156  31.0f, 32.0f, 33.0f,
2157  34.0f, 35.0f, 36.0f,
2158 
2159  37.0f, 38.0f, 39.0f,
2160  40.0f, 41.0f, 42.0f,
2161  43.0f, 44.0f, 45.0f,
2162  46.0f, 47.0f, 48.0f,
2163  49.0f, 50.0f, 51.0f,
2164  52.0f, 53.0f, 54.0f
2165  };
2166 
2167  std::vector<float> input1 =
2168  {
2169  1.0f, 2.0f, 3.0f,
2170  4.0f, 5.0f, 6.0f,
2171  7.0f, 8.0f, 9.0f,
2172  10.0f, 11.0f, 12.0f,
2173  13.0f, 14.0f, 15.0f,
2174  16.0f, 17.0f, 18.0f,
2175 
2176  19.0f, 20.0f, 21.0f,
2177  22.0f, 23.0f, 24.0f,
2178  25.0f, 26.0f, 27.0f,
2179  28.0f, 29.0f, 30.0f,
2180  31.0f, 32.0f, 33.0f,
2181  34.0f, 35.0f, 36.0f
2182  };
2183 
2184  std::vector<float> input2 =
2185  {
2186  37.0f, 38.0f, 39.0f,
2187  40.0f, 41.0f, 42.0f,
2188  43.0f, 44.0f, 45.0f,
2189  46.0f, 47.0f, 48.0f,
2190  49.0f, 50.0f, 51.0f,
2191  52.0f, 53.0f, 54.0f,
2192  };
2193 
2194  std::vector<unsigned int> wOrigin1 = {0, 0, 0}; //Extent of the window is defined by size of input[0].
2195  ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2196 
2197  std::vector<unsigned int> wOrigin2 = {2, 0, 0}; //Extent of the window is defined by size of input[1].
2198  ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2199 
2200  std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
2201 
2202  bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2203 
2204  std::unique_ptr<ITensorHandle> inputHandle1 =
2205  subTensorsSupported ?
2206  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2207  tensorHandleFactory.CreateTensorHandle(inputTensorInfo1);
2208 
2209  std::unique_ptr<ITensorHandle> inputHandle2 =
2210  subTensorsSupported ?
2211  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2212  tensorHandleFactory.CreateTensorHandle(inputTensorInfo2);
2213 
2214  ConcatQueueDescriptor data;
2216  AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2217  AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2218  AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2219 
2220  data.m_ViewOrigins.push_back(window1);
2221  data.m_ViewOrigins.push_back(window2);
2222 
2223  std::unique_ptr<IWorkload> workload = workloadFactory.CreateWorkload(LayerType::Concat, data, info);
2224 
2225  inputHandle1->Allocate();
2226  inputHandle2->Allocate();
2227  outputHandle->Allocate();
2228 
2229  CopyDataToITensorHandle(inputHandle1.get(), input1.data());
2230  CopyDataToITensorHandle(inputHandle2.get(), input2.data());
2231 
2232  workload->PostAllocationConfigure();
2233  workload->Execute();
2234 
2235  CopyDataFromITensorHandle(actualOutput.data(), outputHandle.get());
2236 
2237  return LayerTestResult<float, 3>(actualOutput,
2238  expectedOutput,
2239  outputHandle->GetShape(),
2240  outputTensorInfo.GetShape());
2241 }
2242 
2244  IWorkloadFactory& workloadFactory,
2245  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2246  const armnn::ITensorHandleFactory& tensorHandleFactory)
2247 {
2248  return Concat1dTestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2249 }
2250 
2252  IWorkloadFactory& workloadFactory,
2253  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2254  const armnn::ITensorHandleFactory& tensorHandleFactory)
2255 {
2256  return Concat2dDim0TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2257 }
2258 
2260  IWorkloadFactory& workloadFactory,
2261  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2262  const armnn::ITensorHandleFactory& tensorHandleFactory)
2263 {
2264  return Concat2dDim1TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2265 }
2266 
2268  IWorkloadFactory& workloadFactory,
2269  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2270  const armnn::ITensorHandleFactory& tensorHandleFactory)
2271 {
2272  return Concat2dDim0DiffInputDimsTestImpl<DataType::Float32>(workloadFactory, memoryManager,
2273  tensorHandleFactory, 0.0f, 0);
2274 }
2275 
2277  IWorkloadFactory& workloadFactory,
2278  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2279  const armnn::ITensorHandleFactory& tensorHandleFactory)
2280 {
2281  return Concat2dDim1DiffInputDimsTestImpl<DataType::Float32>(workloadFactory,
2282  memoryManager,
2283  tensorHandleFactory,
2284  0.0f,
2285  0);
2286 }
2287 
2289  IWorkloadFactory& workloadFactory,
2290  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2291  const armnn::ITensorHandleFactory& tensorHandleFactory)
2292 {
2293  return Concat3dDim0TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2294 }
2295 
2297  IWorkloadFactory& workloadFactory,
2298  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2299  const armnn::ITensorHandleFactory& tensorHandleFactory)
2300 {
2301  return Concat3dDim1TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2302 }
2303 
2305  IWorkloadFactory& workloadFactory,
2306  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2307  const armnn::ITensorHandleFactory& tensorHandleFactory,
2308  bool useSubtensor)
2309 {
2310  return Concat3dDim2TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory,
2311  useSubtensor, 0.0f, 0);
2312 }
2313 
2315  IWorkloadFactory& workloadFactory,
2316  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2317  const armnn::ITensorHandleFactory& tensorHandleFactory)
2318 {
2319  return Concat3dDim0DiffInputDimsTestImpl<DataType::Float32>(
2320  workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2321 }
2322 
2324  IWorkloadFactory& workloadFactory,
2325  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2326  const armnn::ITensorHandleFactory& tensorHandleFactory)
2327 {
2328  return Concat3dDim1DiffInputDimsTestImpl<DataType::Float32>(workloadFactory, memoryManager,
2329  tensorHandleFactory, 0.0f, 0);
2330 }
2331 
2333  IWorkloadFactory& workloadFactory,
2334  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2335  const armnn::ITensorHandleFactory& tensorHandleFactory,
2336  bool useSubtensor)
2337 {
2338  return Concat3dDim2DiffInputDimsTestImpl<DataType::Float32>(
2339  workloadFactory, memoryManager, tensorHandleFactory, useSubtensor, 0.0f, 0);
2340 }
2341 
2343  IWorkloadFactory& workloadFactory,
2344  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2345  const armnn::ITensorHandleFactory& tensorHandleFactory)
2346 {
2347  return Concat4dDim0TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2348 }
2349 
2351  IWorkloadFactory& workloadFactory,
2352  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2353  const armnn::ITensorHandleFactory& tensorHandleFactory)
2354 {
2355  return Concat4dDim1TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2356 }
2357 
2359  IWorkloadFactory& workloadFactory,
2360  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2361  const armnn::ITensorHandleFactory& tensorHandleFactory)
2362 {
2363  return Concat4dDim2TestImpl<DataType::Float32>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2364 }
2365 
2367  IWorkloadFactory& workloadFactory,
2368  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2369  const armnn::ITensorHandleFactory& tensorHandleFactory,
2370  bool useSubtensor)
2371 {
2372  return Concat4dDim3TestImpl<DataType::Float32>(workloadFactory, memoryManager,
2373  tensorHandleFactory, 0.0f, 0, useSubtensor);
2374 }
2375 
2377  IWorkloadFactory& workloadFactory,
2378  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2379  const armnn::ITensorHandleFactory& tensorHandleFactory)
2380 {
2381  return Concat4dDiffShapeDim0TestImpl<DataType::Float32>(workloadFactory, memoryManager,
2382  tensorHandleFactory, 0.0f, 0);
2383 }
2384 
2386  IWorkloadFactory& workloadFactory,
2387  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2388  const armnn::ITensorHandleFactory& tensorHandleFactory)
2389 {
2390  return Concat4dDiffShapeDim1TestImpl<DataType::Float32>(
2391  workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2392 }
2393 
2395  IWorkloadFactory& workloadFactory,
2396  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2397  const armnn::ITensorHandleFactory& tensorHandleFactory)
2398 {
2399  return Concat4dDiffShapeDim2TestImpl<DataType::Float32>(workloadFactory, memoryManager,
2400  tensorHandleFactory, 0.0f, 0);
2401 }
2402 
2404  IWorkloadFactory& workloadFactory,
2405  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2406  const armnn::ITensorHandleFactory& tensorHandleFactory,
2407  bool useSubtensor)
2408 {
2409  return Concat4dDiffShapeDim3TestImpl<DataType::Float32>(
2410  workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0, useSubtensor);
2411 }
2412 
2414  IWorkloadFactory& workloadFactory,
2415  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2416  const armnn::ITensorHandleFactory& tensorHandleFactory)
2417 {
2418  return Concat3dDim1TestImpl<DataType::Float16>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2419 }
2420 
2422  IWorkloadFactory& workloadFactory,
2423  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2424  const armnn::ITensorHandleFactory& tensorHandleFactory)
2425 {
2426  return Concat3dDim1TestImpl<DataType::BFloat16>(workloadFactory, memoryManager, tensorHandleFactory, 0.0f, 0);
2427 }
2428 
2430  IWorkloadFactory& workloadFactory,
2431  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2432  const armnn::ITensorHandleFactory& tensorHandleFactory)
2433 {
2434  IgnoreUnused(memoryManager);
2435 
2436  unsigned int outputWidth = 3;
2437  unsigned int outputHeight = 6;
2438  unsigned int outputChannels = 3;
2439 
2440  unsigned int inputWidth1 = 3;
2441  unsigned int inputHeight1 = 6;
2442  unsigned int inputChannels1 = 2;
2443 
2444  unsigned int inputWidth2 = 3;
2445  unsigned int inputHeight2 = 6;
2446  unsigned int inputChannels2 = 1;
2447 
2448  // Defines the tensor descriptors.
2449  TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, DataType::QAsymmU8);
2450  TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, DataType::QAsymmU8);
2451  TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, DataType::QAsymmU8);
2452 
2453  // Quantized input1 tensor. Range [-3, 1]
2454  const float inputScale1 = 0.015686f;
2455  const int32_t inputOffset1 = 192;
2456 
2457  std::vector<uint8_t> input1 =
2458  {
2459  1, 2, 3,
2460  4, 5, 6,
2461  7, 8, 9,
2462  10, 11, 12,
2463  13, 14, 15,
2464  16, 17, 18,
2465 
2466  19, 20, 21,
2467  22, 23, 24,
2468  25, 26, 27,
2469  28, 29, 30,
2470  31, 32, 33,
2471  34, 35, 36
2472  };
2473 
2474  // Quatized input2 tensor. Range [-1, 4]
2475  const float inputScale2 = 0.019608f;
2476  const int32_t inputOffset2 = 50;
2477 
2478  std::vector<uint8_t> input2 =
2479  {
2480  37, 38, 39,
2481  40, 41, 42,
2482  43, 44, 45,
2483  46, 47, 48,
2484  49, 50, 51,
2485  52, 53, 54
2486  };
2487 
2488  // Output has the same quantization parameters than input1,
2489  // so that only the requantization of input2 is required
2490  const float outputScale = 0.015686f;
2491  const int32_t outputOffset = 192;
2492 
2493  std::vector<uint8_t> actualOutput(outputTensorInfo.GetNumElements());
2494 
2495  std::vector<uint8_t> expectedOutput =
2496  {
2497  1, 2, 3,
2498  4, 5, 6,
2499  7, 8, 9,
2500  10, 11, 12,
2501  13, 14, 15,
2502  16, 17, 18,
2503 
2504  19, 20, 21,
2505  22, 23, 24,
2506  25, 26, 27,
2507  28, 29, 30,
2508  31, 32, 33,
2509  34, 35, 36,
2510 
2511  176, 177, 178,
2512  179, 181, 182,
2513  183, 184, 186,
2514  187, 188, 189,
2515  191, 192, 193,
2516  195, 196, 197
2517  };
2518 
2519  outputTensorInfo.SetQuantizationScale(outputScale);
2520  outputTensorInfo.SetQuantizationOffset(outputOffset);
2521  inputTensorInfo1.SetQuantizationScale(inputScale1);
2522  inputTensorInfo1.SetQuantizationOffset(inputOffset1);
2523  inputTensorInfo2.SetQuantizationScale(inputScale2);
2524  inputTensorInfo2.SetQuantizationOffset(inputOffset2);
2525 
2526  std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
2527  ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2528 
2529  std::vector<unsigned int> wOrigin2 = { 2, 0, 0 }; //Extent of the window is defined by size of input[1].
2530  ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2531 
2532  std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
2533 
2534  bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2535 
2536  std::unique_ptr<ITensorHandle> inputHandle1 =
2537  subTensorsSupported ?
2538  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2539  tensorHandleFactory.CreateTensorHandle(inputTensorInfo1);
2540 
2541  std::unique_ptr<ITensorHandle> inputHandle2 =
2542  subTensorsSupported ?
2543  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2544  tensorHandleFactory.CreateTensorHandle(inputTensorInfo2);
2545 
2546  ConcatQueueDescriptor data;
2548  AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2549  AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2550  AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2551 
2552  data.m_ViewOrigins.push_back(window1);
2553  data.m_ViewOrigins.push_back(window2);
2554 
2555  std::unique_ptr<IWorkload> workload = workloadFactory.CreateWorkload(LayerType::Concat, data, info);
2556 
2557  inputHandle1->Allocate();
2558  inputHandle2->Allocate();
2559  outputHandle->Allocate();
2560 
2561  CopyDataToITensorHandle(inputHandle1.get(), input1.data());
2562  CopyDataToITensorHandle(inputHandle2.get(), input2.data());
2563 
2564  workload->PostAllocationConfigure();
2565  workload->Execute();
2566 
2567  CopyDataFromITensorHandle(actualOutput.data(), outputHandle.get());
2568 
2569  return LayerTestResult<uint8_t, 3>(actualOutput,
2570  expectedOutput,
2571  outputHandle->GetShape(),
2572  outputTensorInfo.GetShape());
2573 }
2574 
2576  IWorkloadFactory& workloadFactory,
2577  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2578  const armnn::ITensorHandleFactory& tensorHandleFactory)
2579 {
2580  IgnoreUnused(memoryManager);
2581 
2582  unsigned int outputWidth = 3;
2583  unsigned int outputHeight = 6;
2584  unsigned int outputChannels = 3;
2585 
2586  unsigned int inputWidth1 = 3;
2587  unsigned int inputHeight1 = 6;
2588  unsigned int inputChannels1 = 2;
2589 
2590  unsigned int inputWidth2 = 3;
2591  unsigned int inputHeight2 = 6;
2592  unsigned int inputChannels2 = 1;
2593 
2594  // Defines the tensor descriptors.
2595  TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, DataType::QAsymmU8);
2596  TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, DataType::QAsymmU8);
2597  TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, DataType::QAsymmU8);
2598 
2599  // Arbitrary scale and offsets. They don't really matter as the Concat operator doesn't dequantize/quantize them.
2600  const float scale = 0.13497836f;
2601  const int32_t offset = -7;
2602 
2603  outputTensorInfo.SetQuantizationScale(scale);
2604  outputTensorInfo.SetQuantizationOffset(offset);
2605  inputTensorInfo1.SetQuantizationScale(scale);
2606  inputTensorInfo1.SetQuantizationOffset(offset);
2607  inputTensorInfo2.SetQuantizationScale(scale);
2608  inputTensorInfo2.SetQuantizationOffset(offset);
2609 
2610  std::vector<uint8_t> actualOutput(outputTensorInfo.GetNumElements());
2611 
2612  std::vector<uint8_t> expectedOutput =
2613  {
2614  1, 2, 3,
2615  4, 5, 6,
2616  7, 8, 9,
2617  10, 11, 12,
2618  13, 14, 15,
2619  16, 17, 18,
2620 
2621  19, 20, 21,
2622  22, 23, 24,
2623  25, 26, 27,
2624  28, 29, 30,
2625  31, 32, 33,
2626  34, 35, 36,
2627 
2628  37, 38, 39,
2629  40, 41, 42,
2630  43, 44, 45,
2631  46, 47, 48,
2632  49, 50, 51,
2633  52, 53, 54
2634  };
2635 
2636  std::vector<uint8_t> input1 =
2637  {
2638  1, 2, 3,
2639  4, 5, 6,
2640  7, 8, 9,
2641  10, 11, 12,
2642  13, 14, 15,
2643  16, 17, 18,
2644 
2645  19, 20, 21,
2646  22, 23, 24,
2647  25, 26, 27,
2648  28, 29, 30,
2649  31, 32, 33,
2650  34, 35, 36
2651  };
2652 
2653  std::vector<uint8_t> input2 =
2654  {
2655  37, 38, 39,
2656  40, 41, 42,
2657  43, 44, 45,
2658  46, 47, 48,
2659  49, 50, 51,
2660  52, 53, 54
2661  };
2662 
2663  std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
2664  ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2665 
2666  std::vector<unsigned int> wOrigin2 = { 2, 0, 0 }; //Extent of the window is defined by size of input[1].
2667  ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2668 
2669  std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
2670 
2671  bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2672 
2673  std::unique_ptr<ITensorHandle> inputHandle1 =
2674  subTensorsSupported ?
2675  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2676  tensorHandleFactory.CreateTensorHandle(inputTensorInfo1);
2677 
2678  std::unique_ptr<ITensorHandle> inputHandle2 =
2679  subTensorsSupported ?
2680  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2681  tensorHandleFactory.CreateTensorHandle(inputTensorInfo2);
2682 
2683 
2684  ConcatQueueDescriptor data;
2686  AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2687  AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2688  AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2689 
2690  data.m_ViewOrigins.push_back(window1);
2691  data.m_ViewOrigins.push_back(window2);
2692 
2693  std::unique_ptr<IWorkload> workload = workloadFactory.CreateWorkload(LayerType::Concat, data, info);
2694 
2695  inputHandle1->Allocate();
2696  inputHandle2->Allocate();
2697  outputHandle->Allocate();
2698 
2699  CopyDataToITensorHandle(inputHandle1.get(), input1.data());
2700  CopyDataToITensorHandle(inputHandle2.get(), input2.data());
2701 
2702  workload->PostAllocationConfigure();
2703  workload->Execute();
2704 
2705  CopyDataFromITensorHandle(actualOutput.data(), outputHandle.get());
2706 
2707  return LayerTestResult<uint8_t, 3>(actualOutput,
2708  expectedOutput,
2709  outputHandle->GetShape(),
2710  outputTensorInfo.GetShape());
2711 }
2712 
2714  IWorkloadFactory& workloadFactory,
2715  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2716  const armnn::ITensorHandleFactory& tensorHandleFactory)
2717 {
2718  IgnoreUnused(memoryManager);
2719 
2720  unsigned int outputWidth = 3;
2721  unsigned int outputHeight = 6;
2722  unsigned int outputChannels = 3;
2723 
2724  unsigned int inputWidth1 = 3;
2725  unsigned int inputHeight1 = 6;
2726  unsigned int inputChannels1 = 2;
2727 
2728  unsigned int inputWidth2 = 3;
2729  unsigned int inputHeight2 = 6;
2730  unsigned int inputChannels2 = 1;
2731 
2732  // Defines the tensor descriptors.
2733  TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, DataType::QSymmS16);
2734  TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, DataType::QSymmS16);
2735  TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, DataType::QSymmS16);
2736 
2737  // Arbitrary scale and offsets. They don't really matter as the Concat operator doesn't dequantize/quantize them.
2738  const float scale = 0.13497836f;
2739  const int32_t offset = -7;
2740 
2741  outputTensorInfo.SetQuantizationScale(scale);
2742  outputTensorInfo.SetQuantizationOffset(offset);
2743  inputTensorInfo1.SetQuantizationScale(scale);
2744  inputTensorInfo1.SetQuantizationOffset(offset);
2745  inputTensorInfo2.SetQuantizationScale(scale);
2746  inputTensorInfo2.SetQuantizationOffset(offset);
2747 
2748  std::vector<uint16_t> actualOutput(outputTensorInfo.GetNumElements());
2749 
2750  std::vector<uint16_t> expectedOutput =
2751  {
2752  1, 2, 3,
2753  4, 5, 6,
2754  7, 8, 9,
2755  10, 11, 12,
2756  13, 14, 15,
2757  16, 17, 18,
2758 
2759  19, 20, 21,
2760  22, 23, 24,
2761  25, 26, 27,
2762  28, 29, 30,
2763  31, 32, 33,
2764  34, 35, 36,
2765 
2766  37, 38, 39,
2767  40, 41, 42,
2768  43, 44, 45,
2769  46, 47, 48,
2770  49, 50, 51,
2771  52, 53, 54
2772  };
2773 
2774  std::vector<uint16_t> input1 =
2775  {
2776  1, 2, 3,
2777  4, 5, 6,
2778  7, 8, 9,
2779  10, 11, 12,
2780  13, 14, 15,
2781  16, 17, 18,
2782 
2783  19, 20, 21,
2784  22, 23, 24,
2785  25, 26, 27,
2786  28, 29, 30,
2787  31, 32, 33,
2788  34, 35, 36,
2789  };
2790 
2791  std::vector<uint16_t> input2 =
2792  {
2793  37, 38, 39,
2794  40, 41, 42,
2795  43, 44, 45,
2796  46, 47, 48,
2797  49, 50, 51,
2798  52, 53, 54,
2799  };
2800 
2801  std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
2802  ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2803 
2804  std::vector<unsigned int> wOrigin2 = { 2, 0, 0 }; //Extent of the window is defined by size of input[1].
2805  ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2806 
2807 
2808  std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
2809 
2810  bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2811 
2812  std::unique_ptr<ITensorHandle> inputHandle1 =
2813  subTensorsSupported ?
2814  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2815  tensorHandleFactory.CreateTensorHandle(inputTensorInfo1);
2816 
2817  std::unique_ptr<ITensorHandle> inputHandle2 =
2818  subTensorsSupported ?
2819  tensorHandleFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2820  tensorHandleFactory.CreateTensorHandle(inputTensorInfo2);
2821 
2822 
2823  ConcatQueueDescriptor data;
2825  AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2826  AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2827  AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2828 
2829  data.m_ViewOrigins.push_back(window1);
2830  data.m_ViewOrigins.push_back(window2);
2831 
2832  std::unique_ptr<IWorkload> workload = workloadFactory.CreateWorkload(LayerType::Concat, data, info);
2833 
2834  inputHandle1->Allocate();
2835  inputHandle2->Allocate();
2836  outputHandle->Allocate();
2837 
2838  CopyDataToITensorHandle(inputHandle1.get(), input1.data());
2839  CopyDataToITensorHandle(inputHandle2.get(), input2.data());
2840 
2841  workload->PostAllocationConfigure();
2842  workload->Execute();
2843 
2844  CopyDataFromITensorHandle(actualOutput.data(), outputHandle.get());
2845 
2846  return LayerTestResult<uint16_t, 3>(actualOutput,
2847  expectedOutput,
2848  outputHandle->GetShape(),
2849  outputTensorInfo.GetShape());
2850 }
2851 
2853  IWorkloadFactory& workloadFactory,
2854  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2855  const armnn::ITensorHandleFactory& tensorHandleFactory)
2856 {
2857  return Concat1dTestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2858 }
2859 
2861  IWorkloadFactory& workloadFactory,
2862  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2863  const armnn::ITensorHandleFactory& tensorHandleFactory)
2864 {
2865  return Concat2dDim0TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2866 }
2867 
2869  IWorkloadFactory& workloadFactory,
2870  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2871  const armnn::ITensorHandleFactory& tensorHandleFactory)
2872 {
2873  return Concat2dDim1TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2874 }
2875 
2877  IWorkloadFactory& workloadFactory,
2878  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2879  const armnn::ITensorHandleFactory& tensorHandleFactory)
2880 {
2881  return Concat2dDim0DiffInputDimsTestImpl<DataType::QAsymmU8>(
2882  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2883 }
2884 
2886  IWorkloadFactory& workloadFactory,
2887  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2888  const armnn::ITensorHandleFactory& tensorHandleFactory)
2889 {
2890  return Concat2dDim1DiffInputDimsTestImpl<DataType::QAsymmU8>(
2891  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2892 }
2893 
2895  IWorkloadFactory& workloadFactory,
2896  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2897  const armnn::ITensorHandleFactory& tensorHandleFactory)
2898 {
2899  return Concat3dDim0TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2900 }
2901 
2903  IWorkloadFactory& workloadFactory,
2904  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2905  const armnn::ITensorHandleFactory& tensorHandleFactory)
2906 {
2907  return Concat3dDim1TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2908 }
2909 
2911  IWorkloadFactory& workloadFactory,
2912  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2913  const armnn::ITensorHandleFactory& tensorHandleFactory,
2914  bool useSubtensor)
2915 {
2916  return Concat3dDim2TestImpl<DataType::QAsymmU8>(
2917  workloadFactory, memoryManager, tensorHandleFactory, useSubtensor, 0.5f, -1);
2918 }
2919 
2921  IWorkloadFactory& workloadFactory,
2922  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2923  const armnn::ITensorHandleFactory& tensorHandleFactory)
2924 {
2925  return Concat3dDim0TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2926 }
2927 
2929  IWorkloadFactory& workloadFactory,
2930  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2931  const armnn::ITensorHandleFactory& tensorHandleFactory)
2932 {
2933  return Concat3dDim1DiffInputDimsTestImpl<DataType::QAsymmU8>(
2934  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2935 }
2936 
2938  IWorkloadFactory& workloadFactory,
2939  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2940  const armnn::ITensorHandleFactory& tensorHandleFactory,
2941  bool useSubtensor)
2942 {
2943  return Concat3dDim2DiffInputDimsTestImpl<DataType::QAsymmU8>(
2944  workloadFactory, memoryManager, tensorHandleFactory, useSubtensor, 0.5f, -1);
2945 }
2946 
2948  IWorkloadFactory& workloadFactory,
2949  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2950  const armnn::ITensorHandleFactory& tensorHandleFactory)
2951 {
2952  return Concat4dDim0TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2953 }
2954 
2956  IWorkloadFactory& workloadFactory,
2957  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2958  const armnn::ITensorHandleFactory& tensorHandleFactory)
2959 {
2960  return Concat4dDim1TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2961 }
2962 
2964  IWorkloadFactory& workloadFactory,
2965  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2966  const armnn::ITensorHandleFactory& tensorHandleFactory)
2967 {
2968  return Concat4dDim2TestImpl<DataType::QAsymmU8>(workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2969 }
2970 
2972  IWorkloadFactory& workloadFactory,
2973  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2974  const armnn::ITensorHandleFactory& tensorHandleFactory, bool useSubtensor)
2975 {
2976  return Concat4dDim3TestImpl<DataType::QAsymmU8>(
2977  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1, useSubtensor);
2978 }
2979 
2981  IWorkloadFactory& workloadFactory,
2982  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2983  const armnn::ITensorHandleFactory& tensorHandleFactory)
2984 {
2985  return Concat4dDiffShapeDim0TestImpl<DataType::QAsymmU8>(
2986  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2987 }
2988 
2990  IWorkloadFactory& workloadFactory,
2991  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2992  const armnn::ITensorHandleFactory& tensorHandleFactory)
2993 {
2994  return Concat4dDiffShapeDim1TestImpl<DataType::QAsymmU8>(
2995  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
2996 }
2997 
2999  IWorkloadFactory& workloadFactory,
3000  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3001  const armnn::ITensorHandleFactory& tensorHandleFactory)
3002 {
3003  return Concat4dDiffShapeDim2TestImpl<DataType::QAsymmU8>(
3004  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1);
3005 }
3006 
3008  IWorkloadFactory& workloadFactory,
3009  const IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3010  const armnn::ITensorHandleFactory& tensorHandleFactory,
3011  bool useSubtensor)
3012 {
3013  return Concat4dDiffShapeDim3TestImpl<DataType::QAsymmU8>(
3014  workloadFactory, memoryManager, tensorHandleFactory, 0.5f, -1, useSubtensor);
3015 }
LayerTestResult< uint16_t, 3 > ConcatUint16Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 4 > Concat4dDiffShapeDim3Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
LayerTestResult< float, 3 > Concat3dDim0Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< float, 2 > Concat2dDim0Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< T, 2 > Concat2dDim1TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< float, 4 > Concat4dDim0Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< float, 3 > ConcatTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< T, 4 > Concat4dDim2TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< uint8_t, 3 > Concat3dDim0DiffInputDimsUint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
const TensorShape & GetShape() const
Definition: Tensor.hpp:191
LayerTestResult< uint8_t, 4 > Concat4dDiffShapeDim1Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< T, 2 > Concat2dDim0DiffInputDimsTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< uint8_t, 2 > Concat2dDim0DiffInputDimsUint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 3 > Concat3dDim1DiffInputDimsUint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 3 > Concat3dDim2DiffInputDimsUint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
virtual std::unique_ptr< ITensorHandle > CreateSubTensorHandle(ITensorHandle &parent, TensorShape const &subTensorShape, unsigned int const *subTensorOrigin) const =0
LayerTestResult< float, 2 > Concat2dDim1Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 4 > Concat4dDim1Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 2 > Concat2dDim0Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< BFloat16, 3 > ConcatBFloat16Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< float, 4 > Concat4dDim2Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 2 > Concat2dDim1DiffInputDimsUint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< float, 4 > Concat4dDiffShapeDim1Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< float, 3 > Concat3dDim1DiffInputDimsTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
LayerTestResult< float, 3 > Concat3dDim2DiffInputDimsTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
void Generate3dPermuteVectorForConcat(unsigned int numDimensions, unsigned int &concatDim, std::pair< PermutationVector, PermutationVector > &permutations)
LayerTestResult< T, 4 > Concat4dDiffShapeDim2TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< uint8_t, 4 > Concat4dDim3Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
LayerTestResult< uint8_t, 2 > Concat2dDim1Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
void SetShape(const TensorShape &newShape)
Definition: Tensor.hpp:193
LayerTestResult< T, 2 > Concat2dTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, const TensorInfo &outputTensorInfo, unsigned int dimension, const float qScale, const int32_t qOffset)
LayerTestResult< T, 1 > Concat1dTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
const uint32_t * GetViewOrigin(uint32_t idx) const
Return the view origin at the int value idx.
LayerTestResult< float, 2 > Concat2dDim0DiffInputDimsTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
std::vector< ViewOrigin > m_ViewOrigins
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
LayerTestResult< float, 3 > Concat3dDim1Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
std::shared_ptr< IMemoryManager > IMemoryManagerSharedPtr
LayerTestResult< T, 3 > Concat3dDim0DiffInputDimsTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
void Concatenate(const ConcatQueueDescriptor &data, std::vector< ITensorHandle *> inputs, std::vector< ITensorHandle *> outputs)
Definition: Concatenate.cpp:14
An OriginsDescriptor for the ConcatLayer.
LayerTestResult< float, 4 > Concat4dDiffShapeDim0Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
std::vector< T > m_ExpectedData
void CopyDataFromITensorHandle(void *mem, const armnn::ITensorHandle *tensorHandle)
LayerTestResult< T, 4 > Concat4dDiffShapeDim1TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< uint8_t, 3 > ConcatUint8DifferentQParamsTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:475
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
LayerTestResult< uint8_t, 4 > Concat4dDiffShapeDim0Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< T, 4 > Concat4dTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, const TensorInfo &outputTensorInfo, unsigned int dimension, bool useSubtensor, float qScale, int32_t qOffset)
LayerTestResult< Half, 3 > ConcatFloat16Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
OriginsDescriptor CreateDescriptorForConcat(const std::vector< TensorInfo > &inputTensorInfos, unsigned int concatDim)
LayerTestResult< uint8_t, 3 > Concat3dDim1Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
void PermuteInputsForConcat(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, std::vector< TensorInfo > &inputTensorInfos, std::vector< T *> &inputData, std::vector< std::vector< T >> &inputDataStorage, PermutationVector &permuteVector, unsigned int &concatDim, TensorInfo &outputTensorInfo)
LayerTestResult< T, 3 > Concat3dDim0TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< float, 3 > Concat3dDim2Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
LayerTestResult< T, 3 > Concat3dDim1TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< float, 4 > Concat4dDiffShapeDim2Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
TensorShape ExpandTensorShapeTo3dForPermute(const TensorShape &inputShape)
LayerTestResult< T, 2 > Concat2dDim1DiffInputDimsTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< T, 2 > Concat2dDim0TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
bool IsEqual(const PermutationVector &other) const
Definition: Types.hpp:334
LayerTestResult< float, 4 > Concat4dDim1Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 4 > Concat4dDiffShapeDim2Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< T, 3 > Concat3dDim2TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor, float qScale, int32_t qOffset)
LayerTestResult< float, 3 > Concat3dDim0DiffInputDimsTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< T, 4 > Concat4dDim1TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< T, 4 > Concat4dDiffShapeDim3TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset, bool useSubtensor)
LayerTestResult< float, 4 > Concat4dDim3Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
void CopyDataToITensorHandle(armnn::ITensorHandle *tensorHandle, const void *memory)
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
LayerTestResult< uint8_t, 3 > Concat3dDim0Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
uint32_t GetNumDimensions() const
Get the number of dimensions.
LayerTestResult< uint8_t, 3 > ConcatUint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< T, 3 > Concat3dTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, const TensorInfo &outputTensorInfo, unsigned int dimension, bool useSubtensor, float qScale, int32_t qOffset)
LayerTestResult< uint8_t, 1 > Concat1dUint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< float, 2 > Concat2dDim1DiffInputDimsTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
void PermuteTensorData(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, const PermutationVector &mappings, TensorInfo &inputTensorInfo, const T *inputData, std::vector< T > &outputData)
Contains information about TensorInfos of a layer.
LayerTestResult< T, 3 > Concat3dDim2DiffInputDimsTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor, float qScale, int32_t qOffset)
OriginsDescriptor CreateDescriptorForConcatenation(TensorShapeIt first, TensorShapeIt last, unsigned int concatenationDimension)
Convenience template to create an OriginsDescriptor to use when creating a ConcatLayer for performing...
uint32_t GetNumViews() const
Get the number of views.
LayerTestResult< T, 4 > Concat4dDim0TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
LayerTestResult< uint8_t, 4 > Concat4dDim2Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< uint8_t, 3 > Concat3dDim2Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
LayerTestResult< T, 3 > ConcatDifferentInputOutputQParamTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
LayerTestResult< T, 4 > Concat4dDim3TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset, bool useSubtensor)
virtual std::unique_ptr< IWorkload > CreateWorkload(LayerType type, const QueueDescriptor &descriptor, const WorkloadInfo &info) const
LayerTestResult< T, 3 > Concat3dDim1DiffInputDimsTestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
armnn::TensorShape Permuted(const armnn::TensorShape &srcShape, const armnn::PermutationVector &mappings)
Definition: Permute.cpp:98
virtual std::unique_ptr< ITensorHandle > CreateTensorHandle(const TensorInfo &tensorInfo) const =0
LayerTestResult< float, 4 > Concat4dDiffShapeDim3Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, bool useSubtensor)
LayerTestResult< uint8_t, 4 > Concat4dDim0Uint8Test(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
LayerTestResult< float, 1 > Concat1dTest(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory)
unsigned int GetNumElements() const
Definition: Tensor.hpp:196
bool NeedPermuteForConcat(const std::vector< TensorInfo > &inputTensorInfos, unsigned int concatDim)
void PermuteOutputForConcat(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, const TensorInfo &tensorInfo, const PermutationVector &permuteVector, std::unique_ptr< ITensorHandle > &&inputDataHandle, T *data)
A PermuteDescriptor for the PermuteLayer.
LayerTestResult< T, 4 > Concat4dDiffShapeDim0TestImpl(IWorkloadFactory &workloadFactory, const IBackendInternal::IMemoryManagerSharedPtr &memoryManager, const armnn::ITensorHandleFactory &tensorHandleFactory, float qScale, int32_t qOffset)
virtual bool SupportsSubTensors() const =0