xref: /aosp_15_r20/external/armnn/src/armnnUtils/test/TensorUtilsTest.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2019,2021-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <armnn/Types.hpp>
7 
8 #include <armnnUtils/TensorUtils.hpp>
9 
10 #include <doctest/doctest.h>
11 
12 using namespace armnn;
13 using namespace armnnUtils;
14 
15 TEST_SUITE("TensorUtilsSuite")
16 {
17 TEST_CASE("ExpandDimsAxis0Test")
18 {
19     armnn::TensorShape inputShape({ 2, 3, 4 });
20 
21     // Expand dimension 0
22     armnn::TensorShape outputShape = ExpandDims(inputShape, 0);
23     CHECK(outputShape.GetNumDimensions() == 4);
24     CHECK(outputShape[0] == 1);
25     CHECK(outputShape[1] == 2);
26     CHECK(outputShape[2] == 3);
27     CHECK(outputShape[3] == 4);
28 }
29 
30 TEST_CASE("ExpandDimsAxis1Test")
31 {
32     armnn::TensorShape inputShape({ 2, 3, 4 });
33 
34     // Expand dimension 1
35     armnn::TensorShape outputShape = ExpandDims(inputShape, 1);
36     CHECK(outputShape.GetNumDimensions() == 4);
37     CHECK(outputShape[0] == 2);
38     CHECK(outputShape[1] == 1);
39     CHECK(outputShape[2] == 3);
40     CHECK(outputShape[3] == 4);
41 }
42 
43 TEST_CASE("ExpandDimsAxis2Test")
44 {
45     armnn::TensorShape inputShape({ 2, 3, 4 });
46 
47     // Expand dimension 2
48     armnn::TensorShape outputShape = ExpandDims(inputShape, 2);
49     CHECK(outputShape.GetNumDimensions() == 4);
50     CHECK(outputShape[0] == 2);
51     CHECK(outputShape[1] == 3);
52     CHECK(outputShape[2] == 1);
53     CHECK(outputShape[3] == 4);
54 }
55 
56 TEST_CASE("ExpandDimsAxis3Test")
57 {
58     armnn::TensorShape inputShape({ 2, 3, 4 });
59 
60     // Expand dimension 3
61     armnn::TensorShape outputShape = ExpandDims(inputShape, 3);
62     CHECK(outputShape.GetNumDimensions() == 4);
63     CHECK(outputShape[0] == 2);
64     CHECK(outputShape[1] == 3);
65     CHECK(outputShape[2] == 4);
66     CHECK(outputShape[3] == 1);
67 }
68 
69 TEST_CASE("ExpandDimsNegativeAxis1Test")
70 {
71     armnn::TensorShape inputShape({ 2, 3, 4 });
72 
73     // Expand dimension -1
74     armnn::TensorShape outputShape = ExpandDims(inputShape, -1);
75     CHECK(outputShape.GetNumDimensions() == 4);
76     CHECK(outputShape[0] == 2);
77     CHECK(outputShape[1] == 3);
78     CHECK(outputShape[2] == 4);
79     CHECK(outputShape[3] == 1);
80 }
81 
82 TEST_CASE("ExpandDimsNegativeAxis2Test")
83 {
84     armnn::TensorShape inputShape({ 2, 3, 4 });
85 
86     // Expand dimension -2
87     armnn::TensorShape outputShape = ExpandDims(inputShape, -2);
88     CHECK(outputShape.GetNumDimensions() == 4);
89     CHECK(outputShape[0] == 2);
90     CHECK(outputShape[1] == 3);
91     CHECK(outputShape[2] == 1);
92     CHECK(outputShape[3] == 4);
93 }
94 
95 TEST_CASE("ExpandDimsNegativeAxis3Test")
96 {
97     armnn::TensorShape inputShape({ 2, 3, 4 });
98 
99     // Expand dimension -3
100     armnn::TensorShape outputShape = ExpandDims(inputShape, -3);
101     CHECK(outputShape.GetNumDimensions() == 4);
102     CHECK(outputShape[0] == 2);
103     CHECK(outputShape[1] == 1);
104     CHECK(outputShape[2] == 3);
105     CHECK(outputShape[3] == 4);
106 }
107 
108 TEST_CASE("ExpandDimsNegativeAxis4Test")
109 {
110     armnn::TensorShape inputShape({ 2, 3, 4 });
111 
112     // Expand dimension -4
113     armnn::TensorShape outputShape = ExpandDims(inputShape, -4);
114     CHECK(outputShape.GetNumDimensions() == 4);
115     CHECK(outputShape[0] == 1);
116     CHECK(outputShape[1] == 2);
117     CHECK(outputShape[2] == 3);
118     CHECK(outputShape[3] == 4);
119 }
120 
121 TEST_CASE("ExpandDimsInvalidAxisTest")
122 {
123     armnn::TensorShape inputShape({ 2, 3, 4 });
124 
125     // Invalid expand dimension 4
126     CHECK_THROWS_AS(ExpandDims(inputShape, 4), armnn::InvalidArgumentException);
127 }
128 
129 TEST_CASE("ExpandDimsInvalidNegativeAxisTest")
130 {
131     armnn::TensorShape inputShape({ 2, 3, 4 });
132 
133     // Invalid expand dimension -5
134     CHECK_THROWS_AS(ExpandDims(inputShape, -5), armnn::InvalidArgumentException);
135 }
136 
137 TEST_CASE("ExpandDimsBy1Rank")
138 {
139     armnn::TensorShape inputShape({ 2, 3, 4 });
140 
141     // Expand by 1 dimension
142     armnn::TensorShape outputShape = ExpandDimsToRank(inputShape, 4);
143     CHECK(outputShape.GetNumDimensions() == 4);
144     CHECK(outputShape[0] == 1);
145     CHECK(outputShape[1] == 2);
146     CHECK(outputShape[2] == 3);
147     CHECK(outputShape[3] == 4);
148 }
149 
150 TEST_CASE("ExpandDimsBy2Ranks")
151 {
152     armnn::TensorShape inputShape({ 3, 4 });
153 
154     // Expand 2 dimensions
155     armnn::TensorShape outputShape = ExpandDimsToRank(inputShape, 4);
156     CHECK(outputShape.GetNumDimensions() == 4);
157     CHECK(outputShape[0] == 1);
158     CHECK(outputShape[1] == 1);
159     CHECK(outputShape[2] == 3);
160     CHECK(outputShape[3] == 4);
161 }
162 
163 TEST_CASE("ExpandDimsBy3Ranks")
164 {
165     armnn::TensorShape inputShape({ 4 });
166 
167     // Expand 3 dimensions
168     armnn::TensorShape outputShape = ExpandDimsToRank(inputShape, 4);
169     CHECK(outputShape.GetNumDimensions() == 4);
170     CHECK(outputShape[0] == 1);
171     CHECK(outputShape[1] == 1);
172     CHECK(outputShape[2] == 1);
173     CHECK(outputShape[3] == 4);
174 }
175 
176 TEST_CASE("ExpandDimsInvalidRankAmount")
177 {
178     armnn::TensorShape inputShape({ 2, 3, 4 });
179 
180     // Don't expand because target rank is smaller than current rank
181     armnn::TensorShape outputShape = ExpandDimsToRank(inputShape, 2);
182     CHECK(outputShape.GetNumDimensions() == 3);
183     CHECK(outputShape[0] == 2);
184     CHECK(outputShape[1] == 3);
185     CHECK(outputShape[2] == 4);
186 }
187 
188 TEST_CASE("ExpandDimsToRankInvalidTensorShape")
189 {
190     armnn::TensorShape inputShape({ 2, 3, 4 });
191 
192     // Throw exception because rank 6 tensors are unsupported by armnn
193     CHECK_THROWS_AS(ExpandDimsToRank(inputShape, 6), armnn::InvalidArgumentException);
194 }
195 
196 
197 TEST_CASE("ReduceDimsShapeAll1s")
198 {
199     armnn::TensorShape inputShape({ 1, 1, 1 });
200 
201     // Reduce dimension 2
202     armnn::TensorShape outputShape = ReduceDims(inputShape, 2);
203     CHECK(outputShape.GetNumDimensions() == 2);
204     CHECK(outputShape[0] == 1);
205     CHECK(outputShape[1] == 1);
206 }
207 
208 TEST_CASE("ReduceDimsShapeNotEnough1s")
209 {
210     armnn::TensorShape inputShape({ 1, 2, 1 });
211 
212     // Reduce dimension 1
213     armnn::TensorShape outputShape = ReduceDims(inputShape, 1);
214     CHECK(outputShape.GetNumDimensions() == 2);
215     CHECK(outputShape[0] == 2);
216     CHECK(outputShape[1] == 1);
217 }
218 
219 TEST_CASE("ReduceDimsInfoAll1s")
220 {
221     armnn::TensorInfo inputInfo({ 1, 1, 1 }, DataType::Float32);
222 
223     // Reduce dimension 2
224     armnn::TensorInfo outputInfo = ReduceDims(inputInfo, 2);
225     CHECK(outputInfo.GetShape().GetNumDimensions() == 2);
226     CHECK(outputInfo.GetShape()[0] == 1);
227     CHECK(outputInfo.GetShape()[1] == 1);
228 }
229 
230 TEST_CASE("ReduceDimsInfoNotEnough1s")
231 {
232     armnn::TensorInfo inputInfo({ 1, 2, 1 }, DataType::Float32);
233 
234     // Reduce dimension 1
235     armnn::TensorInfo outputInfo = ReduceDims(inputInfo, 1);
236     CHECK(outputInfo.GetNumDimensions() == 2);
237     CHECK(outputInfo.GetShape()[0] == 2);
238     CHECK(outputInfo.GetShape()[1] == 1);
239 }
240 
241 TEST_CASE("ReduceDimsShapeDimensionGreaterThanSize")
242 {
243     armnn::TensorShape inputShape({ 1, 1, 1 });
244 
245     // Do not reduce because dimension does not exist
246     armnn::TensorShape outputShape = ReduceDims(inputShape, 4);
247     CHECK(outputShape.GetNumDimensions() == 3);
248     CHECK(outputShape[0] == 1);
249     CHECK(outputShape[1] == 1);
250     CHECK(outputShape[2] == 1);
251 }
252 
253 
254 TEST_CASE("ToFloatArrayInvalidDataType")
255 {
256     armnn::TensorInfo info({ 2, 3, 4 }, armnn::DataType::BFloat16);
257     std::vector<uint8_t> data {1,2,3,4,5,6,7,8,9,10};
258 
259     // Invalid argument
260     CHECK_THROWS_AS(ToFloatArray(data, info), armnn::InvalidArgumentException);
261 }
262 
263 TEST_CASE("ToFloatArrayQSymmS8PerAxis")
264 {
265     std::vector<float> quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f };
266     unsigned int quantizationDim = 1;
267 
268     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QSymmS8, quantizationScales, quantizationDim);
269     std::vector<uint8_t> data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 };
270     float expected[] { 10.0f, 24.0f, -37.8f, -46.4f, -10.6f, -19.2f, -25.8f, -30.4f, -6.6f, -11.2f, -13.8f, -14.4f };
271 
272     std::unique_ptr<float[]> result = ToFloatArray(data, info);
273 
274     for (uint i = 0; i < info.GetNumElements(); ++i)
275     {
276         CHECK_EQ(result[i], doctest::Approx(expected[i]));
277     }
278 }
279 
280 TEST_CASE("ToFloatArrayQSymmS8")
281 {
282     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QSymmS8, 0.1f);
283     std::vector<uint8_t> data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 };
284     float expected[] { 10.0f, 12.0f, -12.6f, -11.6f, -10.6f, -9.6f, -8.6f, -7.6f, -6.6f,  -5.6f, -4.6f, -3.6f };
285 
286     std::unique_ptr<float[]> result = ToFloatArray(data, info);
287 
288     for (uint i = 0; i < info.GetNumElements(); ++i)
289     {
290         CHECK_EQ(result[i], doctest::Approx(expected[i]));
291     }
292 }
293 
294 TEST_CASE("ToFloatArrayQAsymmS8PerAxis")
295 {
296     std::vector<float> quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f };
297     unsigned int quantizationDim = 1;
298 
299     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmS8, quantizationScales, quantizationDim);
300     std::vector<uint8_t> data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 };
301     float expected[] { 10.0f, 24.0f, -37.8f, -46.4f, -10.6f, -19.2f, -25.8f, -30.4f, -6.6f, -11.2f, -13.8f, -14.4f };
302 
303     std::unique_ptr<float[]> result = ToFloatArray(data, info);
304 
305     for (uint i = 0; i < info.GetNumElements(); ++i)
306     {
307         CHECK_EQ(result[i], doctest::Approx(expected[i]));
308     }
309 }
310 
311 TEST_CASE("ToFloatArrayQAsymmS8")
312 {
313     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmS8, 0.1f);
314     std::vector<uint8_t> data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 };
315     float expected[] { 10.0f, 12.0f, -12.6f, -11.6f, -10.6f, -9.6f, -8.6f, -7.6f, -6.6f,  -5.6f, -4.6f, -3.6f };
316 
317     std::unique_ptr<float[]> result = ToFloatArray(data, info);
318 
319     for (uint i = 0; i < info.GetNumElements(); ++i)
320     {
321         CHECK_EQ(result[i], doctest::Approx(expected[i]));
322     }
323 }
324 
325 TEST_CASE("ToFloatArrayQASymmU8PerAxis")
326 {
327     std::vector<float> quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f };
328     unsigned int quantizationDim = 1;
329 
330     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmU8, quantizationScales, quantizationDim);
331     std::vector<uint8_t> data { 100, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220 };
332     float expected[] { 10.0f, 24.0f, 39.0f, 56.0f, 15.0f, 32.0f, 51.0f, 72.0f, 19.0f, 40.0f, 63.0f, 88.0f };
333 
334     std::unique_ptr<float[]> result = ToFloatArray(data, info);
335 
336     for (uint i = 0; i < info.GetNumElements(); ++i)
337     {
338         CHECK_EQ(result[i], doctest::Approx(expected[i]));
339     }
340 }
341 
342 TEST_CASE("ToFloatArrayQAsymmU8")
343 {
344     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmU8, 0.1f);
345     std::vector<uint8_t> data { 100, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220 };
346     float expected[] { 10.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f };
347 
348     std::unique_ptr<float[]> result = ToFloatArray(data, info);
349 
350     for (uint i = 0; i < info.GetNumElements(); ++i)
351     {
352         CHECK_EQ(result[i], doctest::Approx(expected[i]));
353     }
354 }
355 
356 TEST_CASE("ToFloatArraySigned32PerAxis")
357 {
358     std::vector<float> quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f };
359     unsigned int quantizationDim = 1;
360 
361     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed32, quantizationScales, quantizationDim);
362     std::vector<uint8_t> data { 100, 0, 0, 0, 120, 0, 0, 0, 130, 0, 0, 0, 140, 0, 0, 0, 150, 0, 0, 0, 160, 0, 0, 0,
363                                 170, 0, 0, 0, 180, 0, 0, 0, 190, 0, 0, 0, 200, 0, 0, 0, 210, 0, 0, 0, 220, 0, 0, 0 };
364     float expected[] { 10.0f, 24.0f, 39.0f, 56.0f, 15.0f, 32.0f, 51.0f, 72.0f, 19.0f, 40.0f, 63.0f, 88.0f };
365 
366     std::unique_ptr<float[]> result = ToFloatArray(data, info);
367 
368     for (uint i = 0; i < info.GetNumElements(); ++i)
369     {
370         CHECK_EQ(result[i], doctest::Approx(expected[i]));
371     }
372 }
373 
374 TEST_CASE("ToFloatArraySigned32")
375 {
376     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed32, 0.1f);
377     std::vector<uint8_t> data { 100, 0, 0, 0, 120, 0, 0, 0, 130, 0, 0, 0, 140, 0, 0, 0, 150, 0, 0, 0, 160, 0, 0, 0,
378                                 170, 0, 0, 0, 180, 0, 0, 0, 190, 0, 0, 0, 200, 0, 0, 0, 210, 0, 0, 0, 220, 0, 0, 0 };
379     float expected[] { 10.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f };
380 
381     std::unique_ptr<float[]> result = ToFloatArray(data, info);
382 
383     for (uint i = 0; i < info.GetNumElements(); ++i)
384     {
385         CHECK_EQ(result[i], doctest::Approx(expected[i]));
386     }
387 }
388 
389 TEST_CASE("ToFloatArraySigned64PerAxis")
390 {
391     std::vector<float> quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f };
392     unsigned int quantizationDim = 1;
393 
394     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed64, quantizationScales, quantizationDim);
395     std::vector<uint8_t> data { 100, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0,
396                                 140, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0,
397                                 170, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0,
398                                 200, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0 };
399     float expected[] { 10.0f, 24.0f, 39.0f, 56.0f, 15.0f, 32.0f, 51.0f, 72.0f, 19.0f, 40.0f, 63.0f, 88.0f };
400 
401     std::unique_ptr<float[]> result = ToFloatArray(data, info);
402 
403     for (uint i = 0; i < info.GetNumElements(); ++i)
404     {
405         CHECK_EQ(result[i], doctest::Approx(expected[i]));
406     }
407 }
408 
409 TEST_CASE("ToFloatArraySigned64")
410 {
411     armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed64, 0.1f);
412     std::vector<uint8_t> data { 100, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0,
413                                 140, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0,
414                                 170, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0,
415                                 200, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0 };
416     float expected[] { 10.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f };
417 
418     std::unique_ptr<float[]> result = ToFloatArray(data, info);
419 
420     for (uint i = 0; i < info.GetNumElements(); ++i)
421     {
422         CHECK_EQ(result[i], doctest::Approx(expected[i]));
423     }
424 }
425 }
426