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_functional.py 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. # -*- coding: utf-8 -*-
  2. # MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  3. #
  4. # Copyright (c) 2014-2020 Megvii Inc. All rights reserved.
  5. #
  6. # Unless required by applicable law or agreed to in writing,
  7. # software distributed under the License is distributed on an
  8. # "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. import numpy as np
  10. import pytest
  11. from helpers import opr_test
  12. import megengine._internal as mgb
  13. import megengine.functional as F
  14. from megengine import Buffer, Parameter, is_cuda_available, jit, tensor
  15. from megengine.test import assertTensorClose
  16. def test_flatten():
  17. data0_shape = (2, 3, 4, 5)
  18. data1_shape = (4, 5, 6, 7)
  19. data0 = np.random.random(data0_shape).astype(np.float32)
  20. data1 = np.random.random(data1_shape).astype(np.float32)
  21. def compare_fn(x, y):
  22. assert x.numpy().shape == y
  23. output0 = (2 * 3 * 4 * 5,)
  24. output1 = (4 * 5 * 6 * 7,)
  25. cases = [{"input": data0, "output": output0}, {"input": data1, "output": output1}]
  26. opr_test(cases, F.flatten, compare_fn=compare_fn)
  27. output0 = (2, 3 * 4 * 5)
  28. output1 = (4, 5 * 6 * 7)
  29. cases = [{"input": data0, "output": output0}, {"input": data1, "output": output1}]
  30. opr_test(cases, F.flatten, compare_fn=compare_fn, start_axis=1)
  31. output0 = (2, 3, 4 * 5)
  32. output1 = (4, 5, 6 * 7)
  33. cases = [{"input": data0, "output": output0}, {"input": data1, "output": output1}]
  34. opr_test(cases, F.flatten, compare_fn=compare_fn, start_axis=2)
  35. output0 = (2, 3 * 4, 5)
  36. output1 = (4, 5 * 6, 7)
  37. cases = [{"input": data0, "output": output0}, {"input": data1, "output": output1}]
  38. opr_test(cases, F.flatten, compare_fn=compare_fn, start_axis=1, end_axis=2)
  39. def test_where():
  40. maskv0 = np.array([[1, 0], [0, 1]], dtype=np.int32)
  41. xv0 = np.array([[1, np.inf], [np.nan, 4]], dtype=np.float32)
  42. yv0 = np.array([[5, 6], [7, 8]], dtype=np.float32)
  43. maskv1 = np.array([[1, 0, 1], [1, 0, 0], [1, 1, 0]], dtype=np.int32)
  44. xv1 = np.array([[1, np.inf, 2], [0, np.nan, 4], [1, 5, 7]], dtype=np.float32)
  45. yv1 = np.array([[5, 6, 9], [2, 7, 8], [2, 1, 9]], dtype=np.float32)
  46. cases = [
  47. {"input": [maskv0, xv0, yv0]},
  48. {"input": [maskv1, xv1, yv1]},
  49. ]
  50. opr_test(cases, F.where, ref_fn=np.where)
  51. maskv2 = np.array([1, 1, 1], dtype=np.int32)
  52. xv2 = np.array([1, 3, 2], dtype=np.float32)
  53. yv2 = np.array([5, 6, 9], dtype=np.float32)
  54. maskv3 = np.array([0, 0, 0], dtype=np.int32)
  55. xv3 = np.array([1, 3, 2], dtype=np.float32)
  56. yv3 = np.array([5, 6, 9], dtype=np.float32)
  57. cases = [
  58. {"input": [maskv2, xv2, yv2]},
  59. {"input": [maskv3, xv3, yv3]},
  60. ]
  61. opr_test(cases, F.where, ref_fn=np.where)
  62. def test_eye():
  63. dtype = np.float32
  64. cases = [{"input": [10, 20]}, {"input": [20, 30]}]
  65. opr_test(cases, F.eye, ref_fn=lambda n, m: np.eye(n, m).astype(dtype), dtype=dtype)
  66. def test_concat():
  67. def get_data_shape(length: int):
  68. return (length, 2, 3)
  69. data1 = np.random.random(get_data_shape(5)).astype("float32")
  70. data2 = np.random.random(get_data_shape(6)).astype("float32")
  71. data3 = np.random.random(get_data_shape(7)).astype("float32")
  72. def run(data1, data2):
  73. return F.concat([data1, data2])
  74. cases = [{"input": [data1, data2]}, {"input": [data1, data3]}]
  75. opr_test(cases, run, ref_fn=lambda x, y: np.concatenate([x, y]))
  76. def test_matrix_mul():
  77. shape1 = (2, 3)
  78. shape2 = (3, 4)
  79. shape3 = (4, 5)
  80. data1 = np.random.random(shape1).astype("float32")
  81. data2 = np.random.random(shape2).astype("float32")
  82. data3 = np.random.random(shape3).astype("float32")
  83. cases = [{"input": [data1, data2]}, {"input": [data2, data3]}]
  84. opr_test(cases, F.matrix_mul, ref_fn=np.matmul)
  85. def test_batched_matrix_mul():
  86. batch_size = 10
  87. shape1 = (batch_size, 2, 3)
  88. shape2 = (batch_size, 3, 4)
  89. shape3 = (batch_size, 4, 5)
  90. data1 = np.random.random(shape1).astype("float32")
  91. data2 = np.random.random(shape2).astype("float32")
  92. data3 = np.random.random(shape3).astype("float32")
  93. cases = [{"input": [data1, data2]}, {"input": [data2, data3]}]
  94. for i in range(0, batch_size):
  95. def compare_fn(x, y):
  96. x.numpy()[i, ...] == y
  97. opr_test(
  98. cases,
  99. F.batched_matrix_mul,
  100. compare_fn=compare_fn,
  101. ref_fn=lambda x, y: np.matmul(x[i, ...], y[i, ...]),
  102. )
  103. def test_sort():
  104. data1_shape = (10, 3)
  105. data2_shape = (12, 2)
  106. data1 = np.random.random(data1_shape).astype(np.float32)
  107. data2 = np.random.random(data2_shape).astype(np.float32)
  108. output0 = [np.sort(data1), np.argsort(data1).astype(np.int32)]
  109. output1 = [np.sort(data2), np.argsort(data2).astype(np.int32)]
  110. cases = [
  111. {"input": data1, "output": output0},
  112. {"input": data2, "output": output1},
  113. ]
  114. opr_test(cases, F.sort)
  115. def test_round():
  116. data1_shape = (15,)
  117. data2_shape = (25,)
  118. data1 = np.random.random(data1_shape).astype(np.float32)
  119. data2 = np.random.random(data2_shape).astype(np.float32)
  120. cases = [{"input": data1}, {"input": data2}]
  121. opr_test(cases, F.round, ref_fn=np.round)
  122. def test_broadcast_to():
  123. input1_shape = (20, 30)
  124. output1_shape = (30, 20, 30)
  125. data1 = np.random.random(input1_shape).astype(np.float32)
  126. input2_shape = (10, 20)
  127. output2_shape = (20, 10, 20)
  128. data2 = np.random.random(input2_shape).astype(np.float32)
  129. def compare_fn(x, y):
  130. assert x.numpy().shape == y
  131. cases = [
  132. {"input": [data1, output1_shape], "output": output1_shape},
  133. {"input": [data2, output2_shape], "output": output2_shape},
  134. ]
  135. opr_test(cases, F.broadcast_to, compare_fn=compare_fn)
  136. def test_linspace():
  137. cases = [
  138. {"input": [1, 9, 9]},
  139. {"input": [3, 10, 8]},
  140. ]
  141. opr_test(
  142. cases,
  143. F.linspace,
  144. ref_fn=lambda start, end, step: np.linspace(start, end, step, dtype=np.float32),
  145. )
  146. cases = [
  147. {"input": [9, 1, 9]},
  148. {"input": [10, 3, 8]},
  149. ]
  150. opr_test(
  151. cases,
  152. F.linspace,
  153. ref_fn=lambda start, end, step: np.linspace(start, end, step, dtype=np.float32),
  154. )
  155. def test_arange():
  156. cases = [
  157. {"input": [1, 9, 1]},
  158. {"input": [2, 10, 2]},
  159. ]
  160. opr_test(
  161. cases,
  162. F.arange,
  163. ref_fn=lambda start, end, step: np.arange(start, end, step, dtype=np.float32),
  164. )
  165. cases = [
  166. {"input": [9, 1, -1]},
  167. {"input": [10, 2, -2]},
  168. ]
  169. opr_test(
  170. cases,
  171. F.arange,
  172. ref_fn=lambda start, end, step: np.arange(start, end, step, dtype=np.float32),
  173. )
  174. cases = [
  175. {"input": [9.3, 1.2, -0.5]},
  176. {"input": [10.3, 2.1, -1.7]},
  177. ]
  178. opr_test(
  179. cases,
  180. F.arange,
  181. ref_fn=lambda start, end, step: np.arange(start, end, step, dtype=np.float32),
  182. )
  183. def test_add_update():
  184. shape = (2, 3)
  185. v = np.random.random(shape).astype(np.float32)
  186. b = Buffer(v)
  187. u = F.add_update(b, 1)
  188. assertTensorClose(u.numpy(), v + 1)
  189. u = F.add_update(b, 1)
  190. assertTensorClose(u.numpy(), v + 2)
  191. x = np.ones((2, 2), dtype=np.float32)
  192. y = x * 0.5
  193. dest = tensor(x)
  194. delta = tensor(y)
  195. r = F.add_update(dest, delta, alpha=tensor(0.9), beta=0.1, bias=0.1)
  196. assertTensorClose(r.numpy(), x * 0.9 + y * 0.1 + 0.1)
  197. def test_add_update_params():
  198. b = np.random.random((2, 3)).astype(np.float32)
  199. y = Buffer(b)
  200. @jit.trace
  201. def f(x):
  202. return F.add_update(y, x)
  203. f(np.zeros((2, 3)).astype(np.float32))
  204. z = Buffer(np.zeros((2, 3)).astype(np.float32))
  205. F.add_update(y, z, beta=0.1)
  206. res = f(np.ones((2, 3)).astype(np.float32))
  207. assertTensorClose(res, b + 1)
  208. def test_cross_entropy_with_softmax():
  209. data1_shape = (1, 2)
  210. label1_shape = (1,)
  211. data2_shape = (1, 3)
  212. label2_shape = (1,)
  213. data1 = np.array([1, 0.5], dtype=np.float32).reshape(data1_shape)
  214. label1 = np.array([1], dtype=np.int32).reshape(label1_shape)
  215. expect1 = F.cross_entropy(F.softmax(tensor(data1)), tensor(label1)).numpy()
  216. data2 = np.array([0.3, 0.4, 0.3], dtype=np.float32).reshape(data2_shape)
  217. label2 = np.array([1], dtype=np.int32).reshape(label2_shape)
  218. expect2 = F.cross_entropy(F.softmax(tensor(data2)), tensor(label2)).numpy()
  219. cases = [
  220. {"input": [data1, label1], "output": expect1,},
  221. {"input": [data2, label2], "output": expect2,},
  222. ]
  223. opr_test(cases, F.cross_entropy_with_softmax)
  224. def test_cross_entropy():
  225. data1_shape = (1, 2)
  226. label1_shape = (1,)
  227. data2_shape = (1, 3)
  228. label2_shape = (1,)
  229. data1 = np.array([0.5, 0.5], dtype=np.float32).reshape(data1_shape)
  230. label1 = np.array([1], dtype=np.int32).reshape(label1_shape)
  231. expect1 = np.array([-np.log(0.5)], dtype=np.float32)
  232. data2 = np.array([0.3, 0.4, 0.3], dtype=np.float32).reshape(data2_shape)
  233. label2 = np.array([1], dtype=np.int32).reshape(label2_shape)
  234. expect2 = np.array([-np.log(0.4)], dtype=np.float32)
  235. cases = [
  236. {"input": [data1, label1], "output": expect1,},
  237. {"input": [data2, label2], "output": expect2,},
  238. ]
  239. opr_test(cases, F.cross_entropy)
  240. def test_binary_cross_entropy():
  241. data1_shape = (2, 2)
  242. label1_shape = (2, 2)
  243. data2_shape = (2, 3)
  244. label2_shape = (2, 3)
  245. def sigmoid(x):
  246. return 1 / (1 + np.exp(-x))
  247. def compare_fn(x, y):
  248. assertTensorClose(x.numpy(), y, max_err=5e-4)
  249. np.random.seed(123)
  250. data1 = sigmoid(np.random.uniform(size=data1_shape).astype(np.float32))
  251. label1 = np.random.uniform(size=label1_shape).astype(np.float32)
  252. expect1 = np.array([0.6361], dtype=np.float32)
  253. np.random.seed(123)
  254. data2 = sigmoid(np.random.uniform(size=data2_shape).astype(np.float32))
  255. label2 = np.random.uniform(size=label2_shape).astype(np.float32)
  256. expect2 = np.array([0.6750], dtype=np.float32)
  257. cases = [
  258. {"input": [data1, label1], "output": expect1,},
  259. {"input": [data2, label2], "output": expect2,},
  260. ]
  261. opr_test(cases, F.binary_cross_entropy, compare_fn=compare_fn)
  262. @pytest.mark.skip
  263. def test_conv_bias():
  264. inp_scale = 0.01
  265. w_scale = 0.02
  266. outp_scale = 0.1
  267. inp_dtype = mgb.dtype.qint8(inp_scale)
  268. w_dtype = mgb.dtype.qint8(w_scale)
  269. b_dtype = mgb.dtype.qint32(inp_scale * w_scale)
  270. out_dtype = mgb.dtype.qint8(outp_scale)
  271. def run(
  272. N,
  273. IC,
  274. OC,
  275. IH,
  276. IW,
  277. KH,
  278. KW,
  279. PH,
  280. PW,
  281. SH,
  282. SW,
  283. has_bias=True,
  284. nonlinear_mode="IDENTITY",
  285. ):
  286. inp_v = np.random.normal(size=(N, IC, IH, IW))
  287. w_v = np.random.normal(size=(OC, IC, KW, KW))
  288. b_v = np.random.normal(size=(1, OC, 1, 1))
  289. inp_scale = mgb.dtype.get_scale(inp_dtype)
  290. w_scale = mgb.dtype.get_scale(w_dtype)
  291. b_scale = mgb.dtype.get_scale(b_dtype)
  292. inpv = mgb.dtype.convert_to_qint8(inp_v * inp_scale, inp_dtype)
  293. wv = mgb.dtype.convert_to_qint8(w_v * w_scale, w_dtype)
  294. bv = mgb.dtype.convert_to_qint32(b_v * b_scale, b_dtype)
  295. inp_int8 = tensor(inpv, dtype=inp_dtype)
  296. w_int8 = Parameter(wv, dtype=w_dtype)
  297. b_int32 = Parameter(bv, dtype=b_dtype)
  298. inp_fp32 = inp_int8.astype("float32")
  299. w_fp32 = w_int8.astype("float32")
  300. b_fp32 = b_int32.astype("float32")
  301. jit.trace.enabled = True
  302. b_symbolic = True
  303. def convert_to_nchw4(var):
  304. return var.reshape(
  305. var.shapeof(0), var.shapeof(1) // 4, 4, var.shapeof(2), var.shapeof(3)
  306. ).dimshuffle(0, 1, 3, 4, 2)
  307. @jit.trace(symbolic=b_symbolic)
  308. def run_conv2d(inp, w, b):
  309. O = F.conv2d(
  310. inp, w, b if has_bias else None, stride=(SH, SW), padding=(PH, PW),
  311. )
  312. if nonlinear_mode == "RELU":
  313. return F.relu(O)
  314. else:
  315. return O
  316. @jit.trace(symbolic=b_symbolic)
  317. def run_conv_bias(inp, w, b, format="NCHW"):
  318. b = b if has_bias else np.zeros_like(b)
  319. if format == "NCHW4":
  320. inp = convert_to_nchw4(inp)
  321. w = convert_to_nchw4(w)
  322. b = F.flatten(b)
  323. return F.conv_bias_activation(
  324. inp,
  325. w,
  326. b,
  327. stride=(SH, SW),
  328. padding=(PH, PW),
  329. dtype=out_dtype,
  330. nonlinear_mode=nonlinear_mode,
  331. )
  332. format = "NCHW4" if is_cuda_available() else "NCHW"
  333. expected = run_conv2d(inp_fp32, w_fp32, b_fp32)
  334. expected = expected.astype(out_dtype).astype("float32")
  335. result = run_conv_bias(inp_int8, w_int8, b_int32, format=format).astype(
  336. "float32"
  337. )
  338. if format == "NCHW4":
  339. result = result.dimshuffle(0, 1, 4, 2, 3)
  340. expected = F.flatten(expected)
  341. result = F.flatten(result)
  342. assertTensorClose(result.numpy(), expected.numpy())
  343. if not is_cuda_available():
  344. run(1, 4, 4, 24, 33, 1, 1, 2, 3, 1, 1, False)
  345. run(10, 12, 24, 46, 46, 1, 1, 2, 1, 3, 1, False)
  346. run(10, 36, 8, 46, 26, 2, 2, 2, 1, 1, 2, False)
  347. run(1, 4, 4, 24, 33, 1, 1, 2, 3, 1, 1)
  348. run(10, 12, 24, 46, 46, 1, 1, 2, 1, 3, 1)
  349. run(10, 36, 8, 46, 26, 2, 2, 2, 1, 1, 2)
  350. run(10, 36, 8, 46, 26, 2, 2, 2, 1, 1, 2, False, "RELU")
  351. run(10, 36, 8, 46, 26, 2, 2, 2, 1, 1, 2, True, "RELU")

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