• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestMetaTensor()34   TestMetaTensor() {}
SetUp()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 
TEST_F(TestMetaTensor,InitTest)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
TEST_F(TestMetaTensor,TypeTest)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
TEST_F(TestMetaTensor,ShapeTest)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 
TEST_F(TestMetaTensor,EqualTest)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:
TestTensor()95   TestTensor() {}
SetUp()96   virtual void SetUp() { UT::InitPythonPath(); }
97 };
98 
BuildInputTensor()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 
TEST_F(TestTensor,PyArrayScalarTest)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 
TEST_F(TestTensor,InitScalarTest)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 
TEST_F(TestTensor,InitTensorPtrTest)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 
TEST_F(TestTensor,InitByTupleTest)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 
TEST_F(TestTensor,EqualTest)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 
TEST_F(TestTensor,ValueEqualTest)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 
TEST_F(TestTensor,PyArrayTest)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 
TEST_F(TestTensor,InitByFloatArrayDataCTest)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 
TEST_F(TestTensor,InitByFloatArrayDataTest)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 
TEST_F(TestTensor,PyArrayDataTest)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 
TEST_F(TestTensor,TensorDataTest)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 
TEST_F(TestTensor,TensorPyCast)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