ArmNN
 21.08
TensorTest.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <armnn/Tensor.hpp>
8 
9 #include <doctest/doctest.h>
10 
11 using namespace armnn;
12 
13 TEST_SUITE("Tensor")
14 {
15 struct TensorInfoFixture
16 {
17  TensorInfoFixture()
18  {
19  unsigned int sizes[] = {6,7,8,9};
20  m_TensorInfo = TensorInfo(4, sizes, DataType::Float32);
21  }
22  ~TensorInfoFixture() {};
23 
24  TensorInfo m_TensorInfo;
25 };
26 
27 TEST_CASE_FIXTURE(TensorInfoFixture, "ConstructShapeUsingListInitialization")
28 {
29  TensorShape listInitializedShape{ 6, 7, 8, 9 };
30  CHECK(listInitializedShape == m_TensorInfo.GetShape());
31 }
32 
33 TEST_CASE_FIXTURE(TensorInfoFixture, "ConstructTensorInfo")
34 {
35  CHECK(m_TensorInfo.GetNumDimensions() == 4);
36  CHECK(m_TensorInfo.GetShape()[0] == 6); // <= Outer most
37  CHECK(m_TensorInfo.GetShape()[1] == 7);
38  CHECK(m_TensorInfo.GetShape()[2] == 8);
39  CHECK(m_TensorInfo.GetShape()[3] == 9); // <= Inner most
40 }
41 
42 TEST_CASE_FIXTURE(TensorInfoFixture, "CopyConstructTensorInfo")
43 {
44  TensorInfo copyConstructed(m_TensorInfo);
45  CHECK(copyConstructed.GetNumDimensions() == 4);
46  CHECK(copyConstructed.GetShape()[0] == 6);
47  CHECK(copyConstructed.GetShape()[1] == 7);
48  CHECK(copyConstructed.GetShape()[2] == 8);
49  CHECK(copyConstructed.GetShape()[3] == 9);
50 }
51 
52 TEST_CASE_FIXTURE(TensorInfoFixture, "TensorInfoEquality")
53 {
54  TensorInfo copyConstructed(m_TensorInfo);
55  CHECK(copyConstructed == m_TensorInfo);
56 }
57 
58 TEST_CASE_FIXTURE(TensorInfoFixture, "TensorInfoInequality")
59 {
60  TensorInfo other;
61  unsigned int sizes[] = {2,3,4,5};
62  other = TensorInfo(4, sizes, DataType::Float32);
63 
64  CHECK(other != m_TensorInfo);
65 }
66 
67 TEST_CASE_FIXTURE(TensorInfoFixture, "TensorInfoAssignmentOperator")
68 {
69  TensorInfo copy;
70  copy = m_TensorInfo;
71  CHECK(copy == m_TensorInfo);
72 }
73 
74 TEST_CASE("CopyNoQuantizationTensorInfo")
75 {
76  TensorInfo infoA;
77  infoA.SetShape({ 5, 6, 7, 8 });
79 
80  TensorInfo infoB;
81  infoB.SetShape({ 5, 6, 7, 8 });
83  infoB.SetQuantizationScale(10.0f);
84  infoB.SetQuantizationOffset(5);
86 
87  CHECK((infoA.GetShape() == TensorShape({ 5, 6, 7, 8 })));
88  CHECK((infoA.GetDataType() == DataType::QAsymmU8));
89  CHECK(infoA.GetQuantizationScale() == 1);
90  CHECK(infoA.GetQuantizationOffset() == 0);
91  CHECK(!infoA.GetQuantizationDim().has_value());
92 
93  CHECK(infoA != infoB);
94  infoA = infoB;
95  CHECK(infoA == infoB);
96 
97  CHECK((infoA.GetShape() == TensorShape({ 5, 6, 7, 8 })));
98  CHECK((infoA.GetDataType() == DataType::QAsymmU8));
99  CHECK(infoA.GetQuantizationScale() == 10.0f);
100  CHECK(infoA.GetQuantizationOffset() == 5);
101  CHECK(infoA.GetQuantizationDim().value() == 1);
102 }
103 
104 TEST_CASE("CopyDifferentQuantizationTensorInfo")
105 {
106  TensorInfo infoA;
107  infoA.SetShape({ 5, 6, 7, 8 });
109  infoA.SetQuantizationScale(10.0f);
110  infoA.SetQuantizationOffset(5);
112 
113  TensorInfo infoB;
114  infoB.SetShape({ 5, 6, 7, 8 });
116  infoB.SetQuantizationScale(11.0f);
117  infoB.SetQuantizationOffset(6);
119 
120  CHECK((infoA.GetShape() == TensorShape({ 5, 6, 7, 8 })));
121  CHECK((infoA.GetDataType() == DataType::QAsymmU8));
122  CHECK(infoA.GetQuantizationScale() == 10.0f);
123  CHECK(infoA.GetQuantizationOffset() == 5);
124  CHECK(infoA.GetQuantizationDim().value() == 1);
125 
126  CHECK(infoA != infoB);
127  infoA = infoB;
128  CHECK(infoA == infoB);
129 
130  CHECK((infoA.GetShape() == TensorShape({ 5, 6, 7, 8 })));
131  CHECK((infoA.GetDataType() == DataType::QAsymmU8));
132  CHECK(infoA.GetQuantizationScale() == 11.0f);
133  CHECK(infoA.GetQuantizationOffset() == 6);
134  CHECK(infoA.GetQuantizationDim().value() == 2);
135 }
136 
137 void CheckTensor(const ConstTensor& t)
138 {
139  t.GetInfo();
140 }
141 
142 TEST_CASE("TensorVsConstTensor")
143 {
144  int mutableDatum = 2;
145  const int immutableDatum = 3;
146 
147  armnn::Tensor uninitializedTensor;
148  armnn::ConstTensor uninitializedTensor2;
149 
150  uninitializedTensor2 = uninitializedTensor;
151 
152  armnn::Tensor t(TensorInfo(), &mutableDatum);
153  armnn::ConstTensor ct(TensorInfo(), &immutableDatum);
154 
155  // Checks that both Tensor and ConstTensor can be passed as a ConstTensor.
156  CheckTensor(t);
157  CheckTensor(ct);
158 }
159 
160 TEST_CASE("ModifyTensorInfo")
161 {
163  info.SetShape({ 5, 6, 7, 8 });
164  CHECK((info.GetShape() == TensorShape({ 5, 6, 7, 8 })));
166  CHECK((info.GetDataType() == DataType::QAsymmU8));
167  info.SetQuantizationScale(10.0f);
168  CHECK(info.GetQuantizationScale() == 10.0f);
169  info.SetQuantizationOffset(5);
170  CHECK(info.GetQuantizationOffset() == 5);
171 }
172 
173 TEST_CASE("TensorShapeOperatorBrackets")
174 {
175  const TensorShape constShape({0,1,2,3});
176  TensorShape shape({0,1,2,3});
177 
178  // Checks version of operator[] which returns an unsigned int.
179  CHECK(shape[2] == 2);
180  shape[2] = 20;
181  CHECK(shape[2] == 20);
182 
183  // Checks the version of operator[] which returns a reference.
184  CHECK(constShape[2] == 2);
185 }
186 
187 TEST_CASE("TensorInfoPerAxisQuantization")
188 {
189  // Old constructor
190  TensorInfo tensorInfo0({ 1, 1 }, DataType::Float32, 2.0f, 1);
191  CHECK(!tensorInfo0.HasMultipleQuantizationScales());
192  CHECK(tensorInfo0.GetQuantizationScale() == 2.0f);
193  CHECK(tensorInfo0.GetQuantizationOffset() == 1);
194  CHECK(tensorInfo0.GetQuantizationScales()[0] == 2.0f);
195  CHECK(!tensorInfo0.GetQuantizationDim().has_value());
196 
197  // Set per-axis quantization scales
198  std::vector<float> perAxisScales{ 3.0f, 4.0f };
199  tensorInfo0.SetQuantizationScales(perAxisScales);
200  CHECK(tensorInfo0.HasMultipleQuantizationScales());
201  CHECK(tensorInfo0.GetQuantizationScales() == perAxisScales);
202 
203  // Set per-tensor quantization scale
204  tensorInfo0.SetQuantizationScale(5.0f);
205  CHECK(!tensorInfo0.HasMultipleQuantizationScales());
206  CHECK(tensorInfo0.GetQuantizationScales()[0] == 5.0f);
207 
208  // Set quantization offset
209  tensorInfo0.SetQuantizationDim(Optional<unsigned int>(1));
210  CHECK(tensorInfo0.GetQuantizationDim().value() == 1);
211 
212  // New constructor
213  perAxisScales = { 6.0f, 7.0f };
214  TensorInfo tensorInfo1({ 1, 1 }, DataType::Float32, perAxisScales, 1);
215  CHECK(tensorInfo1.HasMultipleQuantizationScales());
216  CHECK(tensorInfo1.GetQuantizationOffset() == 0);
217  CHECK(tensorInfo1.GetQuantizationScales() == perAxisScales);
218  CHECK(tensorInfo1.GetQuantizationDim().value() == 1);
219 }
220 
221 TEST_CASE("TensorShape_scalar")
222 {
223  float mutableDatum = 3.1416f;
224 
227  const armnn::Tensor tensor ( info, &mutableDatum );
228 
230  float scalarValue = *reinterpret_cast<float*>(tensor.GetMemoryArea());
231  CHECK_MESSAGE(mutableDatum == scalarValue, "Scalar value is " << scalarValue);
232 
233  armnn::TensorShape shape_equal;
234  armnn::TensorShape shape_different;
235  shape_equal = shape;
236  CHECK(shape_equal == shape);
237  CHECK(shape_different != shape);
238  CHECK_MESSAGE(1 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
239  CHECK_MESSAGE(1 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
240  CHECK(true == shape.GetDimensionSpecificity(0));
241  CHECK(shape.AreAllDimensionsSpecified());
242  CHECK(shape.IsAtLeastOneDimensionSpecified());
243 
244  CHECK(1 == shape[0]);
245  CHECK(1 == tensor.GetShape()[0]);
246  CHECK(1 == tensor.GetInfo().GetShape()[0]);
247  CHECK_THROWS_AS( shape[1], InvalidArgumentException );
248 
249  float newMutableDatum = 42.f;
250  std::memcpy(tensor.GetMemoryArea(), &newMutableDatum, sizeof(float));
251  scalarValue = *reinterpret_cast<float*>(tensor.GetMemoryArea());
252  CHECK_MESSAGE(newMutableDatum == scalarValue, "Scalar value is " << scalarValue);
253 }
254 
255 TEST_CASE("TensorShape_DynamicTensorType1_unknownNumberDimensions")
256 {
257  float mutableDatum = 3.1416f;
258 
261  armnn::Tensor tensor ( info, &mutableDatum );
262 
264  CHECK_THROWS_AS( shape[0], InvalidArgumentException );
265  CHECK_THROWS_AS( shape.GetNumElements(), InvalidArgumentException );
266  CHECK_THROWS_AS( shape.GetNumDimensions(), InvalidArgumentException );
267 
268  armnn::TensorShape shape_equal;
269  armnn::TensorShape shape_different;
270  shape_equal = shape;
271  CHECK(shape_equal == shape);
272  CHECK(shape_different != shape);
273 }
274 
275 TEST_CASE("TensorShape_DynamicTensorType1_unknownAllDimensionsSizes")
276 {
277  float mutableDatum = 3.1416f;
278 
279  armnn::TensorShape shape ( 3, false );
281  armnn::Tensor tensor ( info, &mutableDatum );
282 
284  CHECK_MESSAGE(0 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
285  CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
286  CHECK(false == shape.GetDimensionSpecificity(0));
287  CHECK(false == shape.GetDimensionSpecificity(1));
288  CHECK(false == shape.GetDimensionSpecificity(2));
289  CHECK(!shape.AreAllDimensionsSpecified());
290  CHECK(!shape.IsAtLeastOneDimensionSpecified());
291 
292  armnn::TensorShape shape_equal;
293  armnn::TensorShape shape_different;
294  shape_equal = shape;
295  CHECK(shape_equal == shape);
296  CHECK(shape_different != shape);
297 }
298 
299 TEST_CASE("TensorShape_DynamicTensorType1_unknownSomeDimensionsSizes")
300 {
301  std::vector<float> mutableDatum { 42.f, 42.f, 42.f,
302  0.0f, 0.1f, 0.2f };
303 
304  armnn::TensorShape shape ( {2, 0, 3}, {true, false, true} );
306  armnn::Tensor tensor ( info, &mutableDatum );
307 
308  CHECK(armnn::Dimensionality::Specified == shape.GetDimensionality());
309  CHECK_MESSAGE(6 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
310  CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
311  CHECK(true == shape.GetDimensionSpecificity(0));
312  CHECK(false == shape.GetDimensionSpecificity(1));
313  CHECK(true == shape.GetDimensionSpecificity(2));
314  CHECK(!shape.AreAllDimensionsSpecified());
315  CHECK(shape.IsAtLeastOneDimensionSpecified());
316 
317  CHECK_THROWS_AS(shape[1], InvalidArgumentException);
318  CHECK_THROWS_AS(tensor.GetShape()[1], InvalidArgumentException);
319  CHECK_THROWS_AS(tensor.GetInfo().GetShape()[1], InvalidArgumentException);
320 
321  CHECK(2 == shape[0]);
322  CHECK(2 == tensor.GetShape()[0]);
323  CHECK(2 == tensor.GetInfo().GetShape()[0]);
324  CHECK_THROWS_AS( shape[1], InvalidArgumentException );
325 
326  CHECK(3 == shape[2]);
327  CHECK(3 == tensor.GetShape()[2]);
328  CHECK(3 == tensor.GetInfo().GetShape()[2]);
329 
330  armnn::TensorShape shape_equal;
331  armnn::TensorShape shape_different;
332  shape_equal = shape;
333  CHECK(shape_equal == shape);
334  CHECK(shape_different != shape);
335 }
336 
337 TEST_CASE("TensorShape_DynamicTensorType1_transitionFromUnknownToKnownDimensionsSizes")
338 {
339  std::vector<float> mutableDatum { 42.f, 42.f, 42.f,
340  0.0f, 0.1f, 0.2f };
341 
344  armnn::Tensor tensor ( info, &mutableDatum );
345 
346  // Specify the number of dimensions
347  shape.SetNumDimensions(3);
349  CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
350  CHECK(false == shape.GetDimensionSpecificity(0));
351  CHECK(false == shape.GetDimensionSpecificity(1));
352  CHECK(false == shape.GetDimensionSpecificity(2));
353  CHECK(!shape.AreAllDimensionsSpecified());
354  CHECK(!shape.IsAtLeastOneDimensionSpecified());
355 
356  // Specify dimension 0 and 2.
357  shape.SetDimensionSize(0, 2);
358  shape.SetDimensionSize(2, 3);
359  CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
360  CHECK_MESSAGE(6 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
361  CHECK(true == shape.GetDimensionSpecificity(0));
362  CHECK(false == shape.GetDimensionSpecificity(1));
363  CHECK(true == shape.GetDimensionSpecificity(2));
364  CHECK(!shape.AreAllDimensionsSpecified());
365  CHECK(shape.IsAtLeastOneDimensionSpecified());
366 
367  info.SetShape(shape);
368  armnn::Tensor tensor2( info, &mutableDatum );
369  CHECK(2 == shape[0]);
370  CHECK(2 == tensor2.GetShape()[0]);
371  CHECK(2 == tensor2.GetInfo().GetShape()[0]);
372 
373  CHECK_THROWS_AS(shape[1], InvalidArgumentException);
374  CHECK_THROWS_AS(tensor.GetShape()[1], InvalidArgumentException);
375  CHECK_THROWS_AS(tensor.GetInfo().GetShape()[1], InvalidArgumentException);
376 
377  CHECK(3 == shape[2]);
378  CHECK(3 == tensor2.GetShape()[2]);
379  CHECK(3 == tensor2.GetInfo().GetShape()[2]);
380 
381  armnn::TensorShape shape_equal;
382  armnn::TensorShape shape_different;
383  shape_equal = shape;
384  CHECK(shape_equal == shape);
385  CHECK(shape_different != shape);
386 
387  // Specify dimension 1.
388  shape.SetDimensionSize(1, 5);
389  CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
390  CHECK_MESSAGE(30 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
391  CHECK(true == shape.GetDimensionSpecificity(0));
392  CHECK(true == shape.GetDimensionSpecificity(1));
393  CHECK(true == shape.GetDimensionSpecificity(2));
394  CHECK(shape.AreAllDimensionsSpecified());
395  CHECK(shape.IsAtLeastOneDimensionSpecified());
396 }
397 
398 TEST_CASE("Tensor_emptyConstructors")
399 {
400  auto shape = armnn::TensorShape();
401  CHECK_MESSAGE( 0 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
402  CHECK_MESSAGE( 0 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
403  CHECK( armnn::Dimensionality::Specified == shape.GetDimensionality());
404  CHECK( shape.AreAllDimensionsSpecified());
405  CHECK_THROWS_AS( shape[0], InvalidArgumentException );
406 
407  auto tensor = armnn::Tensor();
408  CHECK_MESSAGE( 0 == tensor.GetNumDimensions(), "Number of dimensions is " << tensor.GetNumDimensions());
409  CHECK_MESSAGE( 0 == tensor.GetNumElements(), "Number of elements is " << tensor.GetNumElements());
410  CHECK_MESSAGE( 0 == tensor.GetShape().GetNumDimensions(), "Number of dimensions is " <<
411  tensor.GetShape().GetNumDimensions());
412  CHECK_MESSAGE( 0 == tensor.GetShape().GetNumElements(), "Number of dimensions is " <<
413  tensor.GetShape().GetNumElements());
414  CHECK( armnn::Dimensionality::Specified == tensor.GetShape().GetDimensionality());
415  CHECK( tensor.GetShape().AreAllDimensionsSpecified());
416  CHECK_THROWS_AS( tensor.GetShape()[0], InvalidArgumentException );
417 }
418 }
TEST_SUITE("TestConstTensorLayerVisitor")
unsigned int GetNumElements() const
Function that calculates the tensor elements by multiplying all dimension size which are Specified...
Definition: Tensor.cpp:181
const TensorShape & GetShape() const
Definition: Tensor.hpp:191
bool AreAllDimensionsSpecified() const
Checks if there is at least one dimension not specified.
Definition: Tensor.cpp:241
Dimensionality GetDimensionality() const
Function that returns the tensor type.
Definition: Tensor.hpp:92
Optional< unsigned int > GetQuantizationDim() const
Definition: Tensor.cpp:496
const TensorShape & GetShape() const
Definition: Tensor.hpp:297
MemoryType GetMemoryArea() const
Definition: Tensor.hpp:305
Copyright (c) 2021 ARM Limited and Contributors.
bool GetDimensionSpecificity(unsigned int i) const
Gets information about if the dimension size has been specified or not.
Definition: Tensor.cpp:211
void SetShape(const TensorShape &newShape)
Definition: Tensor.hpp:193
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:319
TEST_CASE_FIXTURE(ClContextControlFixture, "CopyBetweenNeonAndGpu")
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:480
float GetQuantizationScale() const
Definition: Tensor.cpp:463
DataType GetDataType() const
Definition: Tensor.hpp:198
bool has_value() const noexcept
Definition: Optional.hpp:53
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:327
void SetNumDimensions(unsigned int numDimensions, bool initDimensionsSpecificity=false)
Sets the tensor rank and therefore the Dimensionality is set to Specified if it was not...
Definition: Tensor.cpp:219
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:475
const TensorInfo & GetInfo() const
Definition: Tensor.hpp:295
void SetDataType(DataType type)
Definition: Tensor.hpp:199
void SetQuantizationDim(const Optional< unsigned int > &quantizationDim)
Definition: Tensor.cpp:501
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
void SetDimensionSize(unsigned int i, unsigned int dimensionSize)
Sets the size of the indicated dimension and Specificity for that dimension is set to true...
Definition: Tensor.cpp:232
void SetQuantizationOffset(int32_t offset)
Definition: Tensor.cpp:491
void SetQuantizationScales(const std::vector< float > &scales)
Definition: Tensor.cpp:458
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:195
bool IsAtLeastOneDimensionSpecified() const
Checks if there is at least one dimension specified.
Definition: Tensor.cpp:257