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