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.

test_utils.py 15 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. import pytest
  2. from fastNLP.envs.imports import _NEED_IMPORT_JITTOR, _NEED_IMPORT_PADDLE, _NEED_IMPORT_TORCH
  3. from fastNLP.modules.mix_modules.utils import (
  4. paddle2torch,
  5. torch2paddle,
  6. jittor2torch,
  7. torch2jittor,
  8. )
  9. if _NEED_IMPORT_TORCH:
  10. import torch
  11. if _NEED_IMPORT_PADDLE:
  12. import paddle
  13. if _NEED_IMPORT_JITTOR:
  14. import jittor
  15. ############################################################################
  16. #
  17. # 测试paddle到torch的转换
  18. #
  19. ############################################################################
  20. @pytest.mark.torchpaddle
  21. class TestPaddle2Torch:
  22. def check_torch_tensor(self, tensor, device, requires_grad):
  23. """
  24. 检查张量设备和梯度情况的工具函数
  25. """
  26. assert isinstance(tensor, torch.Tensor)
  27. if device == "cpu":
  28. assert not tensor.is_cuda
  29. else:
  30. assert tensor.is_cuda
  31. assert tensor.device.index == torch.device(device).index
  32. assert tensor.requires_grad == requires_grad
  33. def test_gradient(self):
  34. """
  35. 测试张量转换后的反向传播是否正确
  36. """
  37. x = paddle.to_tensor([1.0, 2.0, 3.0, 4.0, 5.0], stop_gradient=False)
  38. y = paddle2torch(x)
  39. z = 3 * (y ** 2)
  40. z.sum().backward()
  41. assert y.grad.tolist() == [6, 12, 18, 24, 30]
  42. def test_tensor_transfer(self):
  43. """
  44. 测试单个张量的设备和梯度转换是否正确
  45. """
  46. paddle_tensor = paddle.rand((3, 4, 5)).cpu()
  47. res = paddle2torch(paddle_tensor)
  48. self.check_torch_tensor(res, "cpu", not paddle_tensor.stop_gradient)
  49. res = paddle2torch(paddle_tensor, device="cuda:2", no_gradient=None)
  50. self.check_torch_tensor(res, "cuda:2", not paddle_tensor.stop_gradient)
  51. res = paddle2torch(paddle_tensor, device="cuda:1", no_gradient=True)
  52. self.check_torch_tensor(res, "cuda:1", False)
  53. res = paddle2torch(paddle_tensor, device="cuda:1", no_gradient=False)
  54. self.check_torch_tensor(res, "cuda:1", True)
  55. def test_list_transfer(self):
  56. """
  57. 测试张量列表的转换
  58. """
  59. paddle_list = [paddle.rand((6, 4, 2)).cuda(1) for i in range(10)]
  60. res = paddle2torch(paddle_list)
  61. assert isinstance(res, list)
  62. for t in res:
  63. self.check_torch_tensor(t, "cuda:1", False)
  64. res = paddle2torch(paddle_list, device="cpu", no_gradient=False)
  65. assert isinstance(res, list)
  66. for t in res:
  67. self.check_torch_tensor(t, "cpu", True)
  68. def test_tensor_tuple_transfer(self):
  69. """
  70. 测试张量元组的转换
  71. """
  72. paddle_list = [paddle.rand((6, 4, 2)).cuda(1) for i in range(10)]
  73. paddle_tuple = tuple(paddle_list)
  74. res = paddle2torch(paddle_tuple)
  75. assert isinstance(res, tuple)
  76. for t in res:
  77. self.check_torch_tensor(t, "cuda:1", False)
  78. def test_dict_transfer(self):
  79. """
  80. 测试包含复杂结构的字典的转换
  81. """
  82. paddle_dict = {
  83. "tensor": paddle.rand((3, 4)).cuda(0),
  84. "list": [paddle.rand((6, 4, 2)).cuda(0) for i in range(10)],
  85. "dict":{
  86. "list": [paddle.rand((6, 4, 2)).cuda(0) for i in range(10)],
  87. "tensor": paddle.rand((3, 4)).cuda(0)
  88. },
  89. "int": 2,
  90. "string": "test string"
  91. }
  92. res = paddle2torch(paddle_dict)
  93. assert isinstance(res, dict)
  94. self.check_torch_tensor(res["tensor"], "cuda:0", False)
  95. assert isinstance(res["list"], list)
  96. for t in res["list"]:
  97. self.check_torch_tensor(t, "cuda:0", False)
  98. assert isinstance(res["int"], int)
  99. assert isinstance(res["string"], str)
  100. assert isinstance(res["dict"], dict)
  101. assert isinstance(res["dict"]["list"], list)
  102. for t in res["dict"]["list"]:
  103. self.check_torch_tensor(t, "cuda:0", False)
  104. self.check_torch_tensor(res["dict"]["tensor"], "cuda:0", False)
  105. ############################################################################
  106. #
  107. # 测试torch到paddle的转换
  108. #
  109. ############################################################################
  110. @pytest.mark.torchpaddle
  111. class TestTorch2Paddle:
  112. def check_paddle_tensor(self, tensor, device, stop_gradient):
  113. """
  114. 检查得到的paddle张量设备和梯度情况的工具函数
  115. """
  116. assert isinstance(tensor, paddle.Tensor)
  117. if device == "cpu":
  118. assert tensor.place.is_cpu_place()
  119. elif device.startswith("gpu"):
  120. paddle_device = paddle.device._convert_to_place(device)
  121. assert tensor.place.is_gpu_place()
  122. if hasattr(tensor.place, "gpu_device_id"):
  123. # paddle中,有两种Place
  124. # paddle.fluid.core.Place是创建Tensor时使用的类型
  125. # 有函数gpu_device_id获取设备
  126. assert tensor.place.gpu_device_id() == paddle_device.get_device_id()
  127. else:
  128. # 通过_convert_to_place得到的是paddle.CUDAPlace
  129. # 通过get_device_id获取设备
  130. assert tensor.place.get_device_id() == paddle_device.get_device_id()
  131. else:
  132. raise NotImplementedError
  133. assert tensor.stop_gradient == stop_gradient
  134. def test_gradient(self):
  135. """
  136. 测试转换后梯度的反向传播
  137. """
  138. x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0], requires_grad=True)
  139. y = torch2paddle(x)
  140. z = 3 * (y ** 2)
  141. z.sum().backward()
  142. assert y.grad.tolist() == [6, 12, 18, 24, 30]
  143. def test_tensor_transfer(self):
  144. """
  145. 测试单个张量的转换
  146. """
  147. torch_tensor = torch.rand((3, 4, 5))
  148. res = torch2paddle(torch_tensor)
  149. self.check_paddle_tensor(res, "cpu", True)
  150. res = torch2paddle(torch_tensor, device="gpu:2", no_gradient=None)
  151. self.check_paddle_tensor(res, "gpu:2", True)
  152. res = torch2paddle(torch_tensor, device="gpu:2", no_gradient=True)
  153. self.check_paddle_tensor(res, "gpu:2", True)
  154. res = torch2paddle(torch_tensor, device="gpu:2", no_gradient=False)
  155. self.check_paddle_tensor(res, "gpu:2", False)
  156. def test_tensor_list_transfer(self):
  157. """
  158. 测试张量列表的转换
  159. """
  160. torch_list = [torch.rand(6, 4, 2) for i in range(10)]
  161. res = torch2paddle(torch_list)
  162. assert isinstance(res, list)
  163. for t in res:
  164. self.check_paddle_tensor(t, "cpu", True)
  165. res = torch2paddle(torch_list, device="gpu:1", no_gradient=False)
  166. assert isinstance(res, list)
  167. for t in res:
  168. self.check_paddle_tensor(t, "gpu:1", False)
  169. def test_tensor_tuple_transfer(self):
  170. """
  171. 测试张量元组的转换
  172. """
  173. torch_list = [torch.rand(6, 4, 2) for i in range(10)]
  174. torch_tuple = tuple(torch_list)
  175. res = torch2paddle(torch_tuple, device="cpu")
  176. assert isinstance(res, tuple)
  177. for t in res:
  178. self.check_paddle_tensor(t, "cpu", True)
  179. def test_dict_transfer(self):
  180. """
  181. 测试复杂的字典结构的转换
  182. """
  183. torch_dict = {
  184. "tensor": torch.rand((3, 4)),
  185. "list": [torch.rand(6, 4, 2) for i in range(10)],
  186. "dict":{
  187. "list": [torch.rand(6, 4, 2) for i in range(10)],
  188. "tensor": torch.rand((3, 4))
  189. },
  190. "int": 2,
  191. "string": "test string"
  192. }
  193. res = torch2paddle(torch_dict)
  194. assert isinstance(res, dict)
  195. self.check_paddle_tensor(res["tensor"], "cpu", True)
  196. assert isinstance(res["list"], list)
  197. for t in res["list"]:
  198. self.check_paddle_tensor(t, "cpu", True)
  199. assert isinstance(res["int"], int)
  200. assert isinstance(res["string"], str)
  201. assert isinstance(res["dict"], dict)
  202. assert isinstance(res["dict"]["list"], list)
  203. for t in res["dict"]["list"]:
  204. self.check_paddle_tensor(t, "cpu", True)
  205. self.check_paddle_tensor(res["dict"]["tensor"], "cpu", True)
  206. ############################################################################
  207. #
  208. # 测试jittor到torch的转换
  209. #
  210. ############################################################################
  211. @pytest.mark.torchjittor
  212. class TestJittor2Torch:
  213. def check_torch_tensor(self, tensor, device, requires_grad):
  214. """
  215. 检查得到的torch张量的工具函数
  216. """
  217. assert isinstance(tensor, torch.Tensor)
  218. if device == "cpu":
  219. assert not tensor.is_cuda
  220. else:
  221. assert tensor.is_cuda
  222. assert tensor.device.index == torch.device(device).index
  223. assert tensor.requires_grad == requires_grad
  224. def test_var_transfer(self):
  225. """
  226. 测试单个Jittor Var的转换
  227. """
  228. jittor_var = jittor.rand((3, 4, 5))
  229. res = jittor2torch(jittor_var)
  230. if jittor.flags.use_cuda:
  231. self.check_torch_tensor(res, "cuda:0", True)
  232. else:
  233. self.check_torch_tensor(res, "cpu", True)
  234. res = jittor2torch(jittor_var, device="cuda:2", no_gradient=None)
  235. self.check_torch_tensor(res, "cuda:2", True)
  236. res = jittor2torch(jittor_var, device="cuda:2", no_gradient=True)
  237. self.check_torch_tensor(res, "cuda:2", False)
  238. res = jittor2torch(jittor_var, device="cuda:2", no_gradient=False)
  239. self.check_torch_tensor(res, "cuda:2", True)
  240. def test_var_list_transfer(self):
  241. """
  242. 测试Jittor列表的转换
  243. """
  244. jittor_list = [jittor.rand((6, 4, 2)) for i in range(10)]
  245. res = jittor2torch(jittor_list)
  246. assert isinstance(res, list)
  247. for t in res:
  248. if jittor.flags.use_cuda:
  249. self.check_torch_tensor(t, "cuda:0", True)
  250. else:
  251. self.check_torch_tensor(t, "cpu", True)
  252. res = jittor2torch(jittor_list, device="cuda:1", no_gradient=False)
  253. assert isinstance(res, list)
  254. for t in res:
  255. self.check_torch_tensor(t, "cuda:1", True)
  256. def test_var_tuple_transfer(self):
  257. """
  258. 测试Jittor变量元组的转换
  259. """
  260. jittor_list = [jittor.rand((6, 4, 2)) for i in range(10)]
  261. jittor_tuple = tuple(jittor_list)
  262. res = jittor2torch(jittor_tuple, device="cpu")
  263. assert isinstance(res, tuple)
  264. for t in res:
  265. self.check_torch_tensor(t, "cpu", True)
  266. def test_dict_transfer(self):
  267. """
  268. 测试字典结构的转换
  269. """
  270. jittor_dict = {
  271. "tensor": jittor.rand((3, 4)),
  272. "list": [jittor.rand(6, 4, 2) for i in range(10)],
  273. "dict":{
  274. "list": [jittor.rand(6, 4, 2) for i in range(10)],
  275. "tensor": jittor.rand((3, 4))
  276. },
  277. "int": 2,
  278. "string": "test string"
  279. }
  280. res = jittor2torch(jittor_dict)
  281. assert isinstance(res, dict)
  282. if jittor.flags.use_cuda:
  283. self.check_torch_tensor(res["tensor"], "cuda:0", True)
  284. else:
  285. self.check_torch_tensor(res["tensor"], "cpu", True)
  286. assert isinstance(res["list"], list)
  287. for t in res["list"]:
  288. if jittor.flags.use_cuda:
  289. self.check_torch_tensor(t, "cuda:0", True)
  290. else:
  291. self.check_torch_tensor(t, "cpu", True)
  292. assert isinstance(res["int"], int)
  293. assert isinstance(res["string"], str)
  294. assert isinstance(res["dict"], dict)
  295. assert isinstance(res["dict"]["list"], list)
  296. for t in res["dict"]["list"]:
  297. if jittor.flags.use_cuda:
  298. self.check_torch_tensor(t, "cuda:0", True)
  299. else:
  300. self.check_torch_tensor(t, "cpu", True)
  301. if jittor.flags.use_cuda:
  302. self.check_torch_tensor(res["dict"]["tensor"], "cuda:0", True)
  303. else:
  304. self.check_torch_tensor(res["dict"]["tensor"], "cpu", True)
  305. ############################################################################
  306. #
  307. # 测试torch到jittor的转换
  308. #
  309. ############################################################################
  310. @pytest.mark.torchjittor
  311. class TestTorch2Jittor:
  312. def check_jittor_var(self, var, requires_grad):
  313. """
  314. 检查得到的Jittor Var梯度情况的工具函数
  315. """
  316. assert isinstance(var, jittor.Var)
  317. assert var.requires_grad == requires_grad
  318. def test_gradient(self):
  319. """
  320. 测试反向传播的梯度
  321. """
  322. x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0], requires_grad=True)
  323. y = torch2jittor(x)
  324. z = 3 * (y ** 2)
  325. grad = jittor.grad(z, y)
  326. assert grad.tolist() == [6.0, 12.0, 18.0, 24.0, 30.0]
  327. def test_tensor_transfer(self):
  328. """
  329. 测试单个张量转换为Jittor
  330. """
  331. torch_tensor = torch.rand((3, 4, 5))
  332. res = torch2jittor(torch_tensor)
  333. self.check_jittor_var(res, False)
  334. res = torch2jittor(torch_tensor, no_gradient=None)
  335. self.check_jittor_var(res, False)
  336. res = torch2jittor(torch_tensor, no_gradient=True)
  337. self.check_jittor_var(res, False)
  338. res = torch2jittor(torch_tensor, no_gradient=False)
  339. self.check_jittor_var(res, True)
  340. def test_tensor_list_transfer(self):
  341. """
  342. 测试张量列表的转换
  343. """
  344. torch_list = [torch.rand((6, 4, 2)) for i in range(10)]
  345. res = torch2jittor(torch_list)
  346. assert isinstance(res, list)
  347. for t in res:
  348. self.check_jittor_var(t, False)
  349. res = torch2jittor(torch_list, no_gradient=False)
  350. assert isinstance(res, list)
  351. for t in res:
  352. self.check_jittor_var(t, True)
  353. def test_tensor_tuple_transfer(self):
  354. """
  355. 测试张量元组的转换
  356. """
  357. torch_list = [torch.rand((6, 4, 2)) for i in range(10)]
  358. torch_tuple = tuple(torch_list)
  359. res = torch2jittor(torch_tuple)
  360. assert isinstance(res, tuple)
  361. for t in res:
  362. self.check_jittor_var(t, False)
  363. def test_dict_transfer(self):
  364. """
  365. 测试字典结构的转换
  366. """
  367. torch_dict = {
  368. "tensor": torch.rand((3, 4)),
  369. "list": [torch.rand(6, 4, 2) for i in range(10)],
  370. "dict":{
  371. "list": [torch.rand(6, 4, 2) for i in range(10)],
  372. "tensor": torch.rand((3, 4))
  373. },
  374. "int": 2,
  375. "string": "test string"
  376. }
  377. res = torch2jittor(torch_dict)
  378. assert isinstance(res, dict)
  379. self.check_jittor_var(res["tensor"], False)
  380. assert isinstance(res["list"], list)
  381. for t in res["list"]:
  382. self.check_jittor_var(t, False)
  383. assert isinstance(res["int"], int)
  384. assert isinstance(res["string"], str)
  385. assert isinstance(res["dict"], dict)
  386. assert isinstance(res["dict"]["list"], list)
  387. for t in res["dict"]["list"]:
  388. self.check_jittor_var(t, False)
  389. self.check_jittor_var(res["dict"]["tensor"], False)