1 /** 2 * Copyright 2020 Huawei Technologies Co., Ltd 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include <iostream> 17 #include <memory> 18 #include <vector> 19 20 #include "common/common_test.h" 21 #include "common/py_func_graph_fetcher.h" 22 23 #include "securec/include/securec.h" 24 #include "ir/tensor.h" 25 #include "pybind_api/ir/tensor_py.h" 26 27 using mindspore::tensor::TensorPy; 28 29 namespace mindspore { 30 namespace tensor { 31 32 class TestMetaTensor : public UT::Common { 33 public: 34 TestMetaTensor() {} 35 virtual void SetUp() { 36 std::vector<int64_t> dimensions({2, 3}); 37 meta_tensor_ = MetaTensor(TypeId::kNumberTypeFloat64, dimensions); 38 } 39 40 protected: 41 MetaTensor meta_tensor_; 42 }; 43 44 TEST_F(TestMetaTensor, InitTest) { 45 std::vector<int64_t> dimensions({2, 3}); 46 MetaTensor meta_tensor(TypeId::kNumberTypeFloat64, dimensions); 47 48 // Test type 49 ASSERT_EQ(TypeId::kNumberTypeFloat64, meta_tensor.data_type()); 50 51 // Test dimensions 52 ASSERT_EQ(2, meta_tensor.DimensionSize(0)); 53 ASSERT_EQ(3, meta_tensor.DimensionSize(1)); 54 ASSERT_EQ(-1, meta_tensor.DimensionSize(2)); 55 56 // Test number of elements 57 ASSERT_EQ(6, meta_tensor.ElementsNum()); 58 } 59 60 // Test type 61 TEST_F(TestMetaTensor, TypeTest) { 62 meta_tensor_.set_data_type(TypeId::kNumberTypeInt32); 63 ASSERT_EQ(TypeId::kNumberTypeInt32, meta_tensor_.data_type()); 64 } 65 66 // Test shape 67 TEST_F(TestMetaTensor, ShapeTest) { 68 std::vector<int64_t> dimensions({5, 6, 7}); 69 meta_tensor_.set_shape(dimensions); 70 71 ASSERT_EQ(5, meta_tensor_.DimensionSize(0)); 72 ASSERT_EQ(6, meta_tensor_.DimensionSize(1)); 73 ASSERT_EQ(7, meta_tensor_.DimensionSize(2)); 74 75 // Test number of elements 76 ASSERT_EQ(210, meta_tensor_.ElementsNum()); 77 } 78 79 TEST_F(TestMetaTensor, EqualTest) { 80 std::vector<int64_t> dimensions({2, 3}); 81 MetaTensor meta_tensor_x(TypeId::kNumberTypeFloat64, dimensions); 82 MetaTensor meta_tensor_y(meta_tensor_x); 83 84 ASSERT_TRUE(meta_tensor_x == meta_tensor_y); 85 86 MetaTensor meta_tensor_z(TypeId::kNumberTypeFloat32, dimensions); 87 ASSERT_FALSE(meta_tensor_x == meta_tensor_z); 88 89 meta_tensor_z = meta_tensor_x; 90 ASSERT_TRUE(meta_tensor_x == meta_tensor_z); 91 } 92 93 class TestTensor : public UT::Common { 94 public: 95 TestTensor() {} 96 virtual void SetUp() { UT::InitPythonPath(); } 97 }; 98 99 py::array_t<float, py::array::c_style> BuildInputTensor() { 100 // Init tensor data by py::array_t<float> 101 py::array_t<float, py::array::c_style> input = py::array_t<float, py::array::c_style>({2, 3}); 102 auto array = input.mutable_unchecked(); 103 float start = 0; 104 for (int i = 0; i < array.shape(0); i++) { 105 for (int j = 0; j < array.shape(1); j++) { 106 array(i, j) = start++; 107 } 108 } 109 return input; 110 } 111 112 TEST_F(TestTensor, PyArrayScalarTest) { 113 std::vector<int64_t> dimensions; 114 py::array data = py::array_t<int64_t, py::array::c_style>(dimensions); 115 uint8_t *data_buf = reinterpret_cast<uint8_t *>(data.request(true).ptr); 116 117 int64_t num = 1; 118 errno_t ret = memcpy_s(data_buf, sizeof(int64_t), &num, sizeof(int64_t)); 119 120 ASSERT_EQ(0, ret); 121 122 ASSERT_EQ(num, *data_buf); 123 } 124 125 TEST_F(TestTensor, InitScalarTest) { 126 std::vector<int64_t> dimensions; 127 Tensor tensor(TypeId::kNumberTypeInt64, dimensions); 128 uint8_t *data_buf = reinterpret_cast<uint8_t *>(tensor.data_c()); 129 130 int64_t num = 1; 131 errno_t ret = memcpy_s(data_buf, sizeof(int64_t), &num, sizeof(int64_t)); 132 133 ASSERT_EQ(0, ret); 134 135 ASSERT_EQ(num, *data_buf); 136 137 // Test type 138 ASSERT_EQ(TypeId::kNumberTypeInt64, tensor.data_type()); 139 140 // Test dimensions 141 ASSERT_EQ(0, tensor.DataDim()); 142 143 // Test shape 144 ASSERT_EQ(0, tensor.shape().size()); 145 std::vector<int64_t> empty_shape; 146 ASSERT_EQ(empty_shape, tensor.shape()); 147 148 // Test number of elements 149 ASSERT_EQ(1, tensor.ElementsNum()); 150 ASSERT_EQ(1, tensor.DataSize()); 151 } 152 153 TEST_F(TestTensor, InitTensorPtrTest) { 154 std::vector<int64_t> dimensions; 155 Tensor tensor(TypeId::kNumberTypeInt64, dimensions); 156 157 std::shared_ptr<Tensor> tensor_ptr = std::make_shared<Tensor>(tensor); 158 159 // Test type 160 ASSERT_EQ(TypeId::kNumberTypeInt64, tensor_ptr->data_type()); 161 162 // Test dimensions 163 ASSERT_EQ(0, tensor_ptr->DataDim()); 164 165 // Test shape 166 ASSERT_EQ(0, tensor_ptr->shape().size()); 167 std::vector<int64_t> empty_shape; 168 ASSERT_EQ(empty_shape, tensor_ptr->shape()); 169 170 // Test number of elements 171 ASSERT_EQ(1, tensor_ptr->ElementsNum()); 172 ASSERT_EQ(1, tensor_ptr->DataSize()); 173 } 174 175 TEST_F(TestTensor, InitByTupleTest) { 176 const std::vector<int64_t> shape = {2, 3, 4}; 177 TypePtr data_type = kFloat32; 178 Tensor tuple_tensor(data_type->type_id(), shape); 179 ASSERT_EQ(2, tuple_tensor.DimensionSize(0)); 180 ASSERT_EQ(3, tuple_tensor.DimensionSize(1)); 181 ASSERT_EQ(4, tuple_tensor.DimensionSize(2)); 182 183 // Test number of elements 184 ASSERT_EQ(24, tuple_tensor.ElementsNum()); 185 ASSERT_EQ(TypeId::kNumberTypeFloat32, tuple_tensor.data_type()); 186 187 py::tuple tuple = py::make_tuple(1.0, 2.0, 3, 4, 5, 6); 188 TensorPtr tensor = TensorPy::MakeTensor(py::array(tuple), kFloat64); 189 py::array array = TensorPy::AsNumpy(*tensor); 190 191 std::cout << "Dim: " << array.ndim() << std::endl; 192 ASSERT_EQ(1, array.ndim()); 193 194 std::cout << "Num of Elements: " << array.size() << std::endl; 195 ASSERT_EQ(6, array.size()); 196 197 std::cout << "Elements: " << std::endl; 198 // Must be double, or the result is not right 199 double *tensor_data = reinterpret_cast<double *>(tensor->data_c()); 200 for (int i = 0; i < array.size(); i++) { 201 std::cout << tensor_data[i] << std::endl; 202 } 203 } 204 205 TEST_F(TestTensor, EqualTest) { 206 py::tuple tuple = py::make_tuple(1, 2, 3, 4, 5, 6); 207 TensorPtr tensor_int8 = TensorPy::MakeTensor(py::array(tuple), kInt8); 208 ASSERT_TRUE(*tensor_int8 == *tensor_int8); 209 210 ASSERT_EQ(TypeId::kNumberTypeInt8, tensor_int8->data_type_c()); 211 212 TensorPtr tensor_int16 = TensorPy::MakeTensor(py::array(tuple), kInt16); 213 ASSERT_EQ(TypeId::kNumberTypeInt16, tensor_int16->data_type_c()); 214 215 TensorPtr tensor_int32 = TensorPy::MakeTensor(py::array(tuple), kInt32); 216 ASSERT_EQ(TypeId::kNumberTypeInt32, tensor_int32->data_type_c()); 217 218 TensorPtr tensor_float16 = TensorPy::MakeTensor(py::array(tuple), kFloat16); 219 ASSERT_EQ(TypeId::kNumberTypeFloat16, tensor_float16->data_type_c()); 220 221 TensorPtr tensor_float32 = TensorPy::MakeTensor(py::array(tuple), kFloat32); 222 ASSERT_EQ(TypeId::kNumberTypeFloat32, tensor_float32->data_type_c()); 223 224 TensorPtr tensor_float64 = TensorPy::MakeTensor(py::array(tuple), kFloat64); 225 ASSERT_EQ(TypeId::kNumberTypeFloat64, tensor_float64->data_type_c()); 226 } 227 228 TEST_F(TestTensor, ValueEqualTest) { 229 py::tuple tuple = py::make_tuple(1, 2, 3, 4, 5, 6); 230 TensorPtr t1 = TensorPy::MakeTensor(py::array(tuple), kInt32); 231 TensorPtr t2 = TensorPy::MakeTensor(py::array(tuple), kInt32); 232 ASSERT_TRUE(t1->ValueEqual(*t1)); 233 ASSERT_TRUE(t1->ValueEqual(*t2)); 234 235 std::vector<int64_t> shape = {6}; 236 TensorPtr t3 = std::make_shared<Tensor>(kInt32->type_id(), shape); 237 TensorPtr t4 = std::make_shared<Tensor>(kInt32->type_id(), shape); 238 ASSERT_TRUE(t3->ValueEqual(*t3)); 239 ASSERT_FALSE(t3->ValueEqual(*t4)); 240 ASSERT_FALSE(t3->ValueEqual(*t1)); 241 ASSERT_FALSE(t1->ValueEqual(*t3)); 242 243 memcpy_s(t3->data_c(), t3->data().nbytes(), t1->data_c(), t1->data().nbytes()); 244 ASSERT_TRUE(t1->ValueEqual(*t3)); 245 ASSERT_FALSE(t3->ValueEqual(*t4)); 246 ASSERT_FALSE(t4->ValueEqual(*t3)); 247 } 248 249 TEST_F(TestTensor, PyArrayTest) { 250 py::array_t<float, py::array::c_style> input({2, 3}); 251 auto array = input.mutable_unchecked(); 252 float sum = 0; 253 std::cout << "sum" 254 << " = " << std::endl; 255 256 float start = 0; 257 for (int i = 0; i < array.shape(0); i++) { 258 for (int j = 0; j < array.shape(1); j++) { 259 array(i, j) = start++; 260 sum += array(i, j); 261 std::cout << "sum + " 262 << "array[" << i << ", " << j << "]" 263 << " = " << sum << std::endl; 264 } 265 } 266 267 ASSERT_EQ(15, sum); 268 } 269 270 TEST_F(TestTensor, InitByFloatArrayDataCTest) { 271 // Init tensor data by py::array_t<float> 272 auto tensor = TensorPy::MakeTensor(BuildInputTensor()); 273 274 // Print some information of the tensor 275 std::cout << "Datatype: " << tensor->data_type() << std::endl; 276 ASSERT_EQ(TypeId::kNumberTypeFloat32, tensor->data_type()); 277 278 std::cout << "Dim: " << tensor->DataDim() << std::endl; 279 ASSERT_EQ(2, tensor->DataDim()); 280 281 std::cout << "Num of Elements: " << tensor->ElementsNum() << std::endl; 282 ASSERT_EQ(6, tensor->ElementsNum()); 283 284 // Print each elements 285 std::cout << "Elements: " << std::endl; 286 float *tensor_data = reinterpret_cast<float *>(tensor->data_c()); 287 for (int i = 0; i < tensor->ElementsNum(); i++) { 288 std::cout << tensor_data[i] << std::endl; 289 } 290 } 291 292 TEST_F(TestTensor, InitByFloatArrayDataTest) { 293 // Init tensor data by py::array_t<float> 294 TensorPtr tensor = TensorPy::MakeTensor(BuildInputTensor()); 295 296 // Print some information of the tensor 297 std::cout << "Datatype: " << tensor->data_type() << std::endl; 298 ASSERT_EQ(TypeId::kNumberTypeFloat32, tensor->data_type()); 299 300 std::cout << "Dim: " << tensor->DataDim() << std::endl; 301 ASSERT_EQ(2, tensor->DataDim()); 302 303 std::vector<int64_t> dimensions = tensor->shape(); 304 ASSERT_GT(dimensions.size(), 1); 305 std::cout << "Dim0: " << dimensions[0] << std::endl; 306 ASSERT_EQ(2, dimensions[0]); 307 308 std::cout << "Dim1: " << dimensions[1] << std::endl; 309 ASSERT_EQ(3, dimensions[1]); 310 311 std::cout << "Num of Elements: " << tensor->ElementsNum() << std::endl; 312 ASSERT_EQ(6, tensor->ElementsNum()); 313 314 // Print each elements 315 std::cout << "Elements: " << std::endl; 316 py::array_t<float> data = py::cast<py::array_t<float>>(TensorPy::AsNumpy(*tensor)); 317 auto array = data.unchecked<2>(); 318 for (int i = 0; i < array.shape(0); i++) { 319 for (int j = 0; j < array.shape(1); j++) { 320 std::cout << array(i, j) << std::endl; 321 } 322 } 323 } 324 325 TEST_F(TestTensor, PyArrayDataTest) { 326 py::array_t<float, py::array::c_style> input({2, 3}); 327 float *data = reinterpret_cast<float *>(input.request().ptr); 328 float ge_tensor_data[] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6}; 329 errno_t ret = memcpy_s(data, input.nbytes(), ge_tensor_data, sizeof(ge_tensor_data)); 330 ASSERT_EQ(0, ret); 331 auto array = input.mutable_unchecked(); 332 for (int i = 0; i < array.shape(0); i++) { 333 for (int j = 0; j < array.shape(1); j++) { 334 ASSERT_EQ(array(i, j), ge_tensor_data[3 * i + j]); 335 } 336 } 337 } 338 339 TEST_F(TestTensor, TensorDataTest) { 340 // Init a data buffer 341 float ge_tensor_data[] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6}; 342 343 // Create a Tensor with wanted data type and shape 344 Tensor tensor(TypeId::kNumberTypeFloat32, std::vector<int64_t>({2, 3})); 345 346 // Get the writable data pointer from the tensor 347 float *me_tensor_data = reinterpret_cast<float *>(tensor.data_c()); 348 349 // Copy data from buffer to tensor's data 350 errno_t ret = memcpy_s(me_tensor_data, tensor.data().nbytes(), ge_tensor_data, sizeof(ge_tensor_data)); 351 ASSERT_EQ(0, ret); 352 353 // Testify if the data has been copied to the tensor data 354 py::array_t<float> data = py::cast<py::array_t<float>>(TensorPy::AsNumpy(tensor)); 355 auto array = data.mutable_unchecked(); 356 for (int i = 0; i < array.shape(0); i++) { 357 for (int j = 0; j < array.shape(1); j++) { 358 std::cout << "array[" << i << ", " << j << "]" 359 << " = " << array(i, j) << std::endl; 360 ASSERT_EQ(array(i, j), ge_tensor_data[3 * i + j]); 361 } 362 } 363 } 364 365 TEST_F(TestTensor, TensorPyCast) { 366 std::vector<int64_t> shape{2, 3, 4, 5}; 367 py::tuple py_tuple = py::make_tuple(std::make_shared<Tensor>(kNumberTypeFloat32, shape)); 368 auto shape1 = py::cast<Tensor &>(py_tuple[0]).shape(); 369 const py::tuple &t = py_tuple; 370 auto shape2 = py::cast<const Tensor &>(t[0]).shape(); 371 auto shape3 = py::cast<Tensor &>(t[0]).shape(); 372 ASSERT_EQ(shape, shape1); 373 ASSERT_EQ(shape, shape2); 374 ASSERT_EQ(shape, shape3); 375 } 376 377 } // namespace tensor 378 } // namespace mindspore 379