You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tensor.cpp 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /**
  2. * \file src/custom/test/tensor.cpp
  3. * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  4. *
  5. * Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
  6. *
  7. * Unless required by applicable law or agreed to in writing,
  8. * software distributed under the License is distributed on an
  9. * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. */
  11. #include "megbrain_build_config.h"
  12. #if MGB_CUSTOM_OP
  13. #include "megbrain/custom/tensor.h"
  14. #include "megbrain/custom/data_adaptor.h"
  15. #include "megbrain/comp_node.h"
  16. #include "megbrain/tensor.h"
  17. #include "gtest/gtest.h"
  18. #include "megbrain_build_config.h"
  19. #define TENSOR_TEST_LOG 0
  20. using namespace mgb;
  21. namespace custom {
  22. TEST(TestDevice, TestDevice) {
  23. #if MGB_CUDA
  24. ASSERT_TRUE(Device::is_legal("x86"));
  25. ASSERT_TRUE(Device::is_legal(DeviceEnum::cuda));
  26. ASSERT_FALSE(Device::is_legal("cpu"));
  27. Device dev1;
  28. ASSERT_TRUE(dev1.str() == "invalid");
  29. dev1 = "x86";
  30. ASSERT_TRUE("x86" == dev1);
  31. Device dev2 = "cuda";
  32. ASSERT_TRUE(dev2 == "cuda");
  33. ASSERT_FALSE(dev2 == dev1);
  34. Device dev3 = dev2;
  35. ASSERT_TRUE(dev3 == dev2);
  36. ASSERT_FALSE(dev3 == dev1);
  37. Device dev4 = DeviceEnum::cuda;
  38. ASSERT_TRUE(dev4.enumv() == DeviceEnum::cuda);
  39. #if TENSOR_TEST_LOG
  40. std::cout << dev1.str() << "\n" << dev2.str() << "\n"
  41. << dev3.str() << "\n" << dev4.str() << std::endl;
  42. #endif
  43. CompNode compnode = to_builtin<CompNode, Device>(dev3);
  44. ASSERT_TRUE(compnode.to_string_logical() == "gpux:0");
  45. compnode = CompNode::load("cpu0:0");
  46. Device dev5 = to_custom<CompNode, Device>(compnode);
  47. ASSERT_TRUE(dev5.str() == "x86");
  48. std::vector<Device> devs1 = {"x86", "cuda", "x86"};
  49. megdnn::SmallVector<CompNode> compnodes = to_builtin<CompNode, Device>(devs1);
  50. ASSERT_TRUE(compnodes[0].to_string_logical() == "cpux:0");
  51. ASSERT_TRUE(compnodes[1].to_string_logical() == "gpux:0");
  52. ASSERT_TRUE(compnodes[2].to_string_logical() == "cpux:0");
  53. std::vector<Device> devs2 = to_custom<CompNode, Device>(compnodes);
  54. ASSERT_TRUE(devs2[0] == "x86");
  55. ASSERT_TRUE(devs2[1].str() == "cuda");
  56. ASSERT_TRUE(devs2[2] == "x86");
  57. #endif
  58. }
  59. TEST(TestShape, TestShape) {
  60. Shape shape1, shape2;
  61. ASSERT_TRUE(shape1.ndim() == 0);
  62. shape1 = {16, 32, 8, 8};
  63. shape2 = shape1;
  64. ASSERT_TRUE(shape2.ndim() == 4);
  65. ASSERT_TRUE(shape2[0] == 16);
  66. ASSERT_TRUE(shape2[1] == 32);
  67. ASSERT_TRUE(shape2[2] == 8);
  68. ASSERT_TRUE(shape2[3] == 8);
  69. Shape shape3 = {16, 32, 8, 8};
  70. const Shape shape4 = shape1;
  71. ASSERT_TRUE(shape3 == shape4);
  72. shape3[0] = 32;
  73. ASSERT_FALSE(shape3 == shape4);
  74. ASSERT_TRUE(shape3[0] == 32);
  75. ASSERT_TRUE(shape4[0] == 16);
  76. Shape shape5 = {2, 3, 4};
  77. TensorShape bshape1 = to_builtin<TensorShape, Shape>(shape5);
  78. ASSERT_TRUE(bshape1.ndim == 3);
  79. ASSERT_TRUE(bshape1[0] == 2);
  80. ASSERT_TRUE(bshape1[1] == 3);
  81. ASSERT_TRUE(bshape1[2] == 4);
  82. bshape1 = {4, 2, 3};
  83. Shape shape6 = to_custom<TensorShape, Shape>(bshape1);
  84. ASSERT_TRUE(shape6.ndim() == 3);
  85. ASSERT_TRUE(shape6[0] == 4);
  86. ASSERT_TRUE(shape6[1] == 2);
  87. ASSERT_TRUE(shape6[2] == 3);
  88. Shape shape7;
  89. shape7.ndim(3);
  90. shape7[1] = 4;
  91. ASSERT_TRUE(shape7 == Shape({0, 4, 0}));
  92. std::vector<Shape> shapes1 = {{2, 3, 4}, {6}, {5, 7}};
  93. megdnn::SmallVector<TensorShape> bshapes = to_builtin<TensorShape, Shape>(shapes1);
  94. ASSERT_TRUE(bshapes[0].total_nr_elems() == 2*3*4);
  95. ASSERT_TRUE(bshapes[1].total_nr_elems() == 6);
  96. ASSERT_TRUE(bshapes[2].total_nr_elems() == 35);
  97. std::vector<Shape> shapes2 = to_custom<TensorShape, Shape>(bshapes);
  98. ASSERT_TRUE(shapes2[0] == Shape({2, 3, 4}));
  99. ASSERT_TRUE(shapes2[1] == Shape({6}));
  100. ASSERT_TRUE(shapes2[2] == Shape({5, 7}));
  101. }
  102. TEST(TestDType, TestDType) {
  103. #if !MEGDNN_DISABLE_FLOAT16
  104. ASSERT_TRUE(DType::is_legal("uint8"));
  105. ASSERT_TRUE(DType::is_legal(DTypeEnum::bfloat16));
  106. DType dtype1, dtype2;
  107. ASSERT_TRUE(dtype1.str() == "invalid");
  108. dtype1 = "float32";
  109. ASSERT_TRUE(dtype1.str() == "float32");
  110. dtype2 = dtype1;
  111. DType dtype3 = dtype2;
  112. ASSERT_TRUE(dtype3 == dtype1);
  113. ASSERT_TRUE(dtype3 == "float32");
  114. dtype3 = "int8";
  115. ASSERT_FALSE("float32" == dtype3.str());
  116. ASSERT_FALSE(dtype3 == dtype2);
  117. DType dtype4 = DTypeEnum::int8, dtype5 = dtype3;
  118. ASSERT_TRUE(dtype4 == dtype5);
  119. ASSERT_TRUE(dtype4.is_compatible<int8_t>());
  120. ASSERT_FALSE(dtype4.is_compatible<uint8_t>());
  121. DType dtype6 = "int32";
  122. megdnn::DType bdtype1 = to_builtin<megdnn::DType, DType>(dtype6);
  123. ASSERT_TRUE(bdtype1.name() == std::string("Int32"));
  124. bdtype1 = megdnn::DType::from_enum(megdnn::DTypeEnum::BFloat16);
  125. DType dtype7 = to_custom<megdnn::DType, DType>(bdtype1);
  126. ASSERT_TRUE(dtype7.enumv() == DTypeEnum::bfloat16);
  127. std::vector<DType> dtypes1 = {"int8", "uint8", "float16"};
  128. megdnn::SmallVector<megdnn::DType> bdtypes
  129. = to_builtin<megdnn::DType, DType>(dtypes1);
  130. ASSERT_TRUE(bdtypes[0].name() == std::string("Int8"));
  131. ASSERT_TRUE(bdtypes[1].name() == std::string("Uint8"));
  132. ASSERT_TRUE(bdtypes[2].name() == std::string("Float16"));
  133. std::vector<DType> dtypes2 = to_custom<megdnn::DType, DType>(bdtypes);
  134. ASSERT_TRUE(dtypes2[0] == "int8");
  135. ASSERT_TRUE(dtypes2[1] == "uint8");
  136. ASSERT_TRUE(dtypes2[2] == "float16");
  137. #endif
  138. }
  139. TEST(TestDType, TestDTypeQuantized) {
  140. DType quint8_1("quint8", 3.2, 15);
  141. DType quint8_2("quint8", 3.2, 15);
  142. DType quint8_3("quint8", 3.2, 16);
  143. DType quint8_4("quint8", 3.1, 15);
  144. ASSERT_TRUE(quint8_1 == quint8_2);
  145. ASSERT_FALSE(quint8_1 == quint8_3);
  146. ASSERT_FALSE(quint8_1 == quint8_4);
  147. ASSERT_TRUE(quint8_1.scale() == 3.2f);
  148. ASSERT_TRUE(quint8_1.zero_point() == 15);
  149. DType qint8("qint8", 3.3f);
  150. DType qint16("qint16", 3.4f);
  151. DType qint32("qint32", 3.5f);
  152. ASSERT_TRUE(qint8.scale() == 3.3f);
  153. ASSERT_TRUE(qint16.scale() == 3.4f);
  154. ASSERT_TRUE(qint32.scale() == 3.5f);
  155. ASSERT_TRUE(qint8.enumv() == DTypeEnum::qint8);
  156. ASSERT_TRUE(qint8.str() == "qint8");
  157. }
  158. TEST(TestFormat, TestFormat) {
  159. Format format1, format2("default");
  160. ASSERT_TRUE(format1.is_default());
  161. ASSERT_TRUE(format2.is_default());
  162. Format format3 = format1;
  163. ASSERT_TRUE(format3.is_default());
  164. }
  165. TEST(TestTensor, TestTensor) {
  166. CompNode builtin_device = CompNode::load("cpux:0");
  167. TensorShape builtin_shape = {3, 2, 4};
  168. megdnn::DType builtin_dtype = dtype::Int32{};
  169. DeviceTensorND dev_tensor(builtin_device, builtin_shape, builtin_dtype);
  170. Tensor tensor1 = to_custom<DeviceTensorND, Tensor>(dev_tensor);
  171. Tensor tensor2 = to_custom<DeviceTensorND, Tensor>(dev_tensor);
  172. Device device = tensor1.device();
  173. Shape shape = tensor1.shape();
  174. DType dtype = tensor1.dtype();
  175. ASSERT_TRUE(device == "x86");
  176. ASSERT_TRUE(shape.ndim() == 3);
  177. ASSERT_TRUE(shape[0] == 3);
  178. ASSERT_TRUE(shape[1] == 2);
  179. ASSERT_TRUE(shape[2] == 4);
  180. ASSERT_TRUE(shape == std::vector<size_t>({3, 2, 4}));
  181. ASSERT_TRUE(dtype == "int32");
  182. int *raw_ptr1 = tensor1.data<int>();
  183. for (size_t i=0; i<tensor1.size(); i++)
  184. raw_ptr1[i] = i;
  185. int *raw_ptr2 = tensor2.data<int>();
  186. for (size_t i=0; i<tensor2.size(); i++)
  187. ASSERT_TRUE(raw_ptr2[i] == static_cast<int>(i));
  188. Tensor tensor3 = tensor2;
  189. int *raw_ptr3 = tensor3.data<int>();
  190. for (size_t i=0; i<tensor3.size(); i++)
  191. ASSERT_TRUE(raw_ptr3[i] == static_cast<int>(i));
  192. ASSERT_TRUE(raw_ptr1 == raw_ptr2);
  193. ASSERT_TRUE(raw_ptr1 == raw_ptr3);
  194. for (size_t i=0; i<tensor3.size(); i++) {
  195. raw_ptr3[i] = -static_cast<int>(i);
  196. }
  197. for (size_t i=0; i<tensor1.size(); i++) {
  198. ASSERT_TRUE(raw_ptr1[i] == -static_cast<int>(i));
  199. }
  200. DeviceTensorND new_dev_tensor = to_builtin<DeviceTensorND, Tensor>(tensor3);
  201. int *builtin_ptr = new_dev_tensor.ptr<int>();
  202. for (size_t i=0; i<new_dev_tensor.shape().total_nr_elems(); i++) {
  203. ASSERT_TRUE(builtin_ptr[i] == -static_cast<int>(i));
  204. }
  205. }
  206. TEST(TestTensor, TestTensorQuantized) {
  207. #if MGB_CUDA
  208. CompNode builtin_device = CompNode::load("gpux:0");
  209. TensorShape builtin_shape = {3, 2, 4};
  210. megdnn::DType builtin_dtype = dtype::Quantized8Asymm{3.2f, uint8_t(15)};
  211. DeviceTensorND dev_tensor(builtin_device, builtin_shape, builtin_dtype);
  212. Tensor tensor1 = to_custom<DeviceTensorND, Tensor>(dev_tensor);
  213. Tensor tensor2 = to_custom<DeviceTensorND, Tensor>(dev_tensor);
  214. Device device1 = tensor1.device(), device2 = tensor2.device();
  215. Shape shape1 = tensor1.shape(), shape2 = tensor2.shape();
  216. DType dtype1 = tensor1.dtype(), dtype2 = tensor2.dtype();
  217. ASSERT_TRUE(device1 == "cuda");
  218. ASSERT_TRUE(shape1.ndim() == 3);
  219. ASSERT_TRUE(shape1[0] == 3);
  220. ASSERT_TRUE(shape1[1] == 2);
  221. ASSERT_TRUE(shape1[2] == 4);
  222. ASSERT_TRUE(shape1 == std::vector<size_t>({3, 2, 4}));
  223. ASSERT_TRUE(dtype1 == "quint8");
  224. ASSERT_TRUE(dtype1.scale() == 3.2f);
  225. ASSERT_TRUE(dtype1.zero_point() == 15);
  226. ASSERT_TRUE(device1 == device2);
  227. ASSERT_TRUE(shape1 == shape2);
  228. ASSERT_TRUE(dtype1 == dtype2);
  229. #endif
  230. }
  231. TEST(TestTensor, TestTensorAccessorND) {
  232. size_t N = 2, C = 4, H = 6, W = 8;
  233. CompNode builtin_device = CompNode::load("cpux");
  234. TensorShape builtin_shape = {N, C, H, W};
  235. megdnn::DType builtin_dtype = dtype::Int32{};
  236. DeviceTensorND dev_tensor(builtin_device, builtin_shape, builtin_dtype);
  237. int *builtin_ptr = dev_tensor.ptr<int>();
  238. for (size_t i=0; i<dev_tensor.shape().total_nr_elems(); i++) {
  239. builtin_ptr[i] = i;
  240. }
  241. Tensor tensor = to_custom_tensor(dev_tensor);
  242. auto accessor = tensor.accessor<int32_t, 4>();
  243. for (size_t n=0; n<N; ++n) {
  244. for (size_t c=0; c<C; ++c) {
  245. for (size_t h=0; h<H; ++h) {
  246. for (size_t w=0; w<W; ++w) {
  247. int32_t idx = n*C*H*W + c*H*W + h*W + w;
  248. ASSERT_TRUE(accessor[n][c][h][w] == idx);
  249. }
  250. }
  251. }
  252. }
  253. }
  254. TEST(TestTensor, TestTensorAccessor1D) {
  255. CompNode builtin_device = CompNode::load("cpux");
  256. TensorShape builtin_shape = {32};
  257. megdnn::DType builtin_dtype = dtype::Float32{};
  258. DeviceTensorND dev_tensor(builtin_device, builtin_shape, builtin_dtype);
  259. float *builtin_ptr = dev_tensor.ptr<float>();
  260. for (size_t i=0; i<dev_tensor.shape().total_nr_elems(); i++) {
  261. builtin_ptr[i] = i;
  262. }
  263. Tensor tensor = to_custom_tensor(dev_tensor);
  264. auto accessor = tensor.accessor<float, 1>();
  265. for (size_t n=0; n<32; ++n) {
  266. ASSERT_TRUE(accessor[n] == n);
  267. }
  268. }
  269. }
  270. #endif

MegEngine 安装包中集成了使用 GPU 运行代码所需的 CUDA 环境,不用区分 CPU 和 GPU 版。 如果想要运行 GPU 程序,请确保机器本身配有 GPU 硬件设备并安装好驱动。 如果你想体验在云端 GPU 算力平台进行深度学习开发的感觉,欢迎访问 MegStudio 平台