1# Copyright © 2020 Arm Ltd. All rights reserved. 2# SPDX-License-Identifier: MIT 3import pytest 4import numpy as np 5 6import pyarmnn as ann 7 8 9def _get_const_tensor_info(dt): 10 tensor_info = ann.TensorInfo(ann.TensorShape((2, 3)), dt, 0.0, 0, True) 11 12 return tensor_info 13 14 15@pytest.mark.parametrize("dt, data", 16 [ 17 (ann.DataType_Float32, np.random.randint(1, size=(2, 4)).astype(np.float32)), 18 (ann.DataType_Float16, np.random.randint(1, size=(2, 4)).astype(np.float16)), 19 (ann.DataType_QAsymmU8, np.random.randint(1, size=(2, 4)).astype(np.uint8)), 20 (ann.DataType_QAsymmS8, np.random.randint(1, size=(2, 4)).astype(np.int8)), 21 (ann.DataType_QSymmS8, np.random.randint(1, size=(2, 4)).astype(np.int8)), 22 (ann.DataType_Signed32, np.random.randint(1, size=(2, 4)).astype(np.int32)), 23 (ann.DataType_QSymmS16, np.random.randint(1, size=(2, 4)).astype(np.int16)) 24 ], ids=['float32', 'float16', 'unsigned int8', 'signed int8', 'signed int8', 'int32', 'int16']) 25def test_const_tensor_too_many_elements(dt, data): 26 tensor_info = _get_const_tensor_info(dt) 27 num_bytes = tensor_info.GetNumBytes() 28 29 with pytest.raises(ValueError) as err: 30 ann.ConstTensor(tensor_info, data) 31 32 assert 'ConstTensor requires {} bytes, {} provided.'.format(num_bytes, data.nbytes) in str(err.value) 33 34 35@pytest.mark.parametrize("dt, data", 36 [ 37 (ann.DataType_Float32, np.random.randint(1, size=(2, 2)).astype(np.float32)), 38 (ann.DataType_Float16, np.random.randint(1, size=(2, 2)).astype(np.float16)), 39 (ann.DataType_QAsymmU8, np.random.randint(1, size=(2, 2)).astype(np.uint8)), 40 (ann.DataType_QAsymmS8, np.random.randint(1, size=(2, 2)).astype(np.int8)), 41 (ann.DataType_QSymmS8, np.random.randint(1, size=(2, 2)).astype(np.int8)), 42 (ann.DataType_Signed32, np.random.randint(1, size=(2, 2)).astype(np.int32)), 43 (ann.DataType_QSymmS16, np.random.randint(1, size=(2, 2)).astype(np.int16)) 44 ], ids=['float32', 'float16', 'unsigned int8', 'signed int8', 'signed int8', 'int32', 'int16']) 45def test_const_tensor_too_little_elements(dt, data): 46 tensor_info = _get_const_tensor_info(dt) 47 num_bytes = tensor_info.GetNumBytes() 48 49 with pytest.raises(ValueError) as err: 50 ann.ConstTensor(tensor_info, data) 51 52 assert 'ConstTensor requires {} bytes, {} provided.'.format(num_bytes, data.nbytes) in str(err.value) 53 54 55@pytest.mark.parametrize("dt, data", 56 [ 57 (ann.DataType_Float32, np.random.randint(1, size=(2, 2, 3, 3)).astype(np.float32)), 58 (ann.DataType_Float16, np.random.randint(1, size=(2, 2, 3, 3)).astype(np.float16)), 59 (ann.DataType_QAsymmU8, np.random.randint(1, size=(2, 2, 3, 3)).astype(np.uint8)), 60 (ann.DataType_QAsymmS8, np.random.randint(1, size=(2, 2, 3, 3)).astype(np.int8)), 61 (ann.DataType_QSymmS8, np.random.randint(1, size=(2, 2, 3, 3)).astype(np.int8)), 62 (ann.DataType_Signed32, np.random.randint(1, size=(2, 2, 3, 3)).astype(np.int32)), 63 (ann.DataType_QSymmS16, np.random.randint(1, size=(2, 2, 3, 3)).astype(np.int16)) 64 ], ids=['float32', 'float16', 'unsigned int8', 'signed int8', 'signed int8', 'int32', 'int16']) 65def test_const_tensor_multi_dimensional_input(dt, data): 66 tensor = ann.ConstTensor(ann.TensorInfo(ann.TensorShape((2, 2, 3, 3)), dt, 0.0, 0, True), data) 67 68 assert data.size == tensor.GetNumElements() 69 assert data.nbytes == tensor.GetNumBytes() 70 assert dt == tensor.GetDataType() 71 assert tensor.get_memory_area().data 72 73 74def test_create_const_tensor_from_tensor(): 75 tensor_info = ann.TensorInfo(ann.TensorShape((2, 3)), ann.DataType_Float32, 0.0, 0, True) 76 tensor = ann.Tensor(tensor_info) 77 copied_tensor = ann.ConstTensor(tensor) 78 79 assert copied_tensor != tensor, "Different objects" 80 assert copied_tensor.GetInfo() != tensor.GetInfo(), "Different objects" 81 assert copied_tensor.get_memory_area().ctypes.data == tensor.get_memory_area().ctypes.data, "Same memory area" 82 assert copied_tensor.GetNumElements() == tensor.GetNumElements() 83 assert copied_tensor.GetNumBytes() == tensor.GetNumBytes() 84 assert copied_tensor.GetDataType() == tensor.GetDataType() 85 86 87def test_const_tensor_from_tensor_has_memory_area_access_after_deletion_of_original_tensor(): 88 tensor_info = ann.TensorInfo(ann.TensorShape((2, 3)), ann.DataType_Float32, 0.0, 0, True) 89 tensor = ann.Tensor(tensor_info) 90 91 tensor.get_memory_area()[0] = 100 92 93 copied_mem = tensor.get_memory_area().copy() 94 95 assert 100 == copied_mem[0], "Memory was copied correctly" 96 97 copied_tensor = ann.ConstTensor(tensor) 98 99 tensor.get_memory_area()[0] = 200 100 101 assert 200 == tensor.get_memory_area()[0], "Tensor and copied Tensor point to the same memory" 102 assert 200 == copied_tensor.get_memory_area()[0], "Tensor and copied Tensor point to the same memory" 103 104 assert 100 == copied_mem[0], "Copied test memory not affected" 105 106 copied_mem[0] = 200 # modify test memory to equal copied Tensor 107 108 del tensor 109 np.testing.assert_array_equal(copied_tensor.get_memory_area(), copied_mem), "After initial tensor was deleted, " \ 110 "copied Tensor still has " \ 111 "its memory as expected" 112 113 114def test_create_const_tensor_incorrect_args(): 115 with pytest.raises(ValueError) as err: 116 ann.ConstTensor('something', 'something') 117 118 expected_error_message = "Incorrect number of arguments or type of arguments provided to create Const Tensor." 119 assert expected_error_message in str(err.value) 120 121 122@pytest.mark.parametrize("dt, data", 123 [ 124 # -1 not in data type enum 125 (-1, np.random.randint(1, size=(2, 3)).astype(np.float32)), 126 ], ids=['unknown']) 127def test_const_tensor_unsupported_datatype(dt, data): 128 tensor_info = _get_const_tensor_info(dt) 129 130 with pytest.raises(ValueError) as err: 131 ann.ConstTensor(tensor_info, data) 132 133 assert 'The data type provided for this Tensor is not supported: -1' in str(err.value) 134 135 136@pytest.mark.parametrize("dt, data", 137 [ 138 (ann.DataType_Float32, [[1, 1, 1], [1, 1, 1]]), 139 (ann.DataType_Float16, [[1, 1, 1], [1, 1, 1]]), 140 (ann.DataType_QAsymmU8, [[1, 1, 1], [1, 1, 1]]), 141 (ann.DataType_QAsymmS8, [[1, 1, 1], [1, 1, 1]]), 142 (ann.DataType_QSymmS8, [[1, 1, 1], [1, 1, 1]]) 143 ], ids=['float32', 'float16', 'unsigned int8', 'signed int8', 'signed int8']) 144def test_const_tensor_incorrect_input_datatype(dt, data): 145 tensor_info = _get_const_tensor_info(dt) 146 147 with pytest.raises(TypeError) as err: 148 ann.ConstTensor(tensor_info, data) 149 150 assert 'Data must be provided as a numpy array.' in str(err.value) 151 152 153@pytest.mark.parametrize("dt, data", 154 [ 155 (ann.DataType_Float32, np.random.randint(1, size=(2, 3)).astype(np.float32)), 156 (ann.DataType_Float16, np.random.randint(1, size=(2, 3)).astype(np.float16)), 157 (ann.DataType_QAsymmU8, np.random.randint(1, size=(2, 3)).astype(np.uint8)), 158 (ann.DataType_QAsymmS8, np.random.randint(1, size=(2, 3)).astype(np.int8)), 159 (ann.DataType_QSymmS8, np.random.randint(1, size=(2, 3)).astype(np.int8)), 160 (ann.DataType_Signed32, np.random.randint(1, size=(2, 3)).astype(np.int32)), 161 (ann.DataType_QSymmS16, np.random.randint(1, size=(2, 3)).astype(np.int16)) 162 ], ids=['float32', 'float16', 'unsigned int8', 'signed int8', 'signed int8', 'int32', 'int16']) 163class TestNumpyDataTypes: 164 165 def test_copy_const_tensor(self, dt, data): 166 tensor_info = _get_const_tensor_info(dt) 167 tensor = ann.ConstTensor(tensor_info, data) 168 copied_tensor = ann.ConstTensor(tensor) 169 170 assert copied_tensor != tensor, "Different objects" 171 assert copied_tensor.GetInfo() != tensor.GetInfo(), "Different objects" 172 assert copied_tensor.get_memory_area().ctypes.data == tensor.get_memory_area().ctypes.data, "Same memory area" 173 assert copied_tensor.GetNumElements() == tensor.GetNumElements() 174 assert copied_tensor.GetNumBytes() == tensor.GetNumBytes() 175 assert copied_tensor.GetDataType() == tensor.GetDataType() 176 177 def test_const_tensor__str__(self, dt, data): 178 tensor_info = _get_const_tensor_info(dt) 179 d_type = tensor_info.GetDataType() 180 num_dimensions = tensor_info.GetNumDimensions() 181 num_bytes = tensor_info.GetNumBytes() 182 num_elements = tensor_info.GetNumElements() 183 tensor = ann.ConstTensor(tensor_info, data) 184 185 assert str(tensor) == "ConstTensor{{DataType: {}, NumBytes: {}, NumDimensions: " \ 186 "{}, NumElements: {}}}".format(d_type, num_bytes, num_dimensions, num_elements) 187 188 def test_const_tensor_with_info(self, dt, data): 189 tensor_info = _get_const_tensor_info(dt) 190 elements = tensor_info.GetNumElements() 191 num_bytes = tensor_info.GetNumBytes() 192 d_type = dt 193 194 tensor = ann.ConstTensor(tensor_info, data) 195 196 assert tensor_info != tensor.GetInfo(), "Different objects" 197 assert elements == tensor.GetNumElements() 198 assert num_bytes == tensor.GetNumBytes() 199 assert d_type == tensor.GetDataType() 200 201 def test_immutable_memory(self, dt, data): 202 tensor_info = _get_const_tensor_info(dt) 203 204 tensor = ann.ConstTensor(tensor_info, data) 205 206 with pytest.raises(ValueError) as err: 207 tensor.get_memory_area()[0] = 0 208 209 assert 'is read-only' in str(err.value) 210 211 def test_numpy_dtype_matches_ann_dtype(self, dt, data): 212 np_data_type_mapping = {ann.DataType_QAsymmU8: np.uint8, 213 ann.DataType_QAsymmS8: np.int8, 214 ann.DataType_QSymmS8: np.int8, 215 ann.DataType_Float32: np.float32, 216 ann.DataType_QSymmS16: np.int16, 217 ann.DataType_Signed32: np.int32, 218 ann.DataType_Float16: np.float16} 219 220 tensor_info = _get_const_tensor_info(dt) 221 tensor = ann.ConstTensor(tensor_info, data) 222 assert np_data_type_mapping[tensor.GetDataType()] == data.dtype 223 224 225# This test checks that mismatched numpy and PyArmNN datatypes with same number of bits raises correct error. 226@pytest.mark.parametrize("dt, data", 227 [ 228 (ann.DataType_Float32, np.random.randint(1, size=(2, 3)).astype(np.int32)), 229 (ann.DataType_Float16, np.random.randint(1, size=(2, 3)).astype(np.int16)), 230 (ann.DataType_QAsymmU8, np.random.randint(1, size=(2, 3)).astype(np.int8)), 231 (ann.DataType_QAsymmS8, np.random.randint(1, size=(2, 3)).astype(np.uint8)), 232 (ann.DataType_QSymmS8, np.random.randint(1, size=(2, 3)).astype(np.uint8)), 233 (ann.DataType_Signed32, np.random.randint(1, size=(2, 3)).astype(np.float32)), 234 (ann.DataType_QSymmS16, np.random.randint(1, size=(2, 3)).astype(np.float16)) 235 ], ids=['float32', 'float16', 'unsigned int8', 'signed int8', 'signed int8', 'int32', 'int16']) 236def test_numpy_dtype_mismatch_ann_dtype(dt, data): 237 np_data_type_mapping = {ann.DataType_QAsymmU8: np.uint8, 238 ann.DataType_QAsymmS8: np.int8, 239 ann.DataType_QSymmS8: np.int8, 240 ann.DataType_Float32: np.float32, 241 ann.DataType_QSymmS16: np.int16, 242 ann.DataType_Signed32: np.int32, 243 ann.DataType_Float16: np.float16} 244 245 tensor_info = _get_const_tensor_info(dt) 246 with pytest.raises(TypeError) as err: 247 ann.ConstTensor(tensor_info, data) 248 249 assert str(err.value) == "Expected data to have type {} for type {} but instead got numpy.{}".format( 250 np_data_type_mapping[dt], dt, data.dtype) 251 252 253@pytest.mark.parametrize("dt, data", 254 [ 255 (ann.DataType_Float32, np.random.randint(1, size=(2, 3)).astype(np.float32)), 256 (ann.DataType_Float16, np.random.randint(1, size=(2, 3)).astype(np.float16)), 257 (ann.DataType_QAsymmU8, np.random.randint(1, size=(2, 3)).astype(np.uint8)), 258 (ann.DataType_QAsymmS8, np.random.randint(1, size=(2, 3)).astype(np.int8)), 259 (ann.DataType_QSymmS8, np.random.randint(1, size=(2, 3)).astype(np.int8)), 260 (ann.DataType_Signed32, np.random.randint(1, size=(2, 3)).astype(np.int32)), 261 (ann.DataType_QSymmS16, np.random.randint(1, size=(2, 3)).astype(np.int16)) 262 ], ids=['float32', 'float16', 'unsigned int8', 'signed int8', 'signed int8', 'int32', 'int16']) 263class TestConstTensorConstructorErrors: 264 265 def test_tensorinfo_isconstant_not_set(self, dt, data): 266 with pytest.raises(ValueError) as err: 267 ann.ConstTensor(ann.TensorInfo(ann.TensorShape((2, 2, 3, 3)), dt, 0.0, 0, False), data) 268 269 assert str(err.value) == "TensorInfo when initializing ConstTensor must be set to constant." 270 271 def test_tensor_tensorinfo_isconstant_not_set(self, dt, data): 272 with pytest.raises(ValueError) as err: 273 ann.ConstTensor(ann.Tensor(ann.TensorInfo(ann.TensorShape((2, 2, 3, 3)), dt, 0.0, 0, False), data)) 274 275 assert str(err.value) == "TensorInfo of Tensor when initializing ConstTensor must be set to constant."