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_tracing.py 12 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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 io
  10. from tempfile import mkstemp
  11. import numpy as np
  12. import pytest
  13. import megengine.core.tensor.megbrain_graph as G
  14. import megengine.functional as F
  15. import megengine.utils.comp_graph_tools as cgtools
  16. from megengine import tensor
  17. from megengine.core._trace_option import set_symbolic_shape
  18. from megengine.core.ops import builtin as ops
  19. from megengine.core.ops.builtin import Elemwise
  20. from megengine.core.tensor.core import apply
  21. from megengine.core.tensor.raw_tensor import as_raw_tensor
  22. from megengine.functional import exp, log
  23. from megengine.jit import exclude_from_trace, trace
  24. from megengine.random import normal, uniform
  25. def test_trace():
  26. for symbolic in [False, True]:
  27. @trace(symbolic=symbolic)
  28. def f(x):
  29. op = ops.Elemwise(Elemwise.Mode.NEGATE)
  30. (y,) = apply(op, x)
  31. return y
  32. x = as_raw_tensor([1]).numpy()
  33. y = f.__wrapped__(as_raw_tensor(x)).numpy()
  34. for i in range(3):
  35. np.testing.assert_equal(f(as_raw_tensor(x)).numpy(), y)
  36. def test_exclude_from_trace():
  37. for symbolic in [False, True]:
  38. @trace(symbolic=symbolic)
  39. def f(x):
  40. neg = ops.Elemwise(Elemwise.Mode.NEGATE)
  41. (x,) = apply(neg, x)
  42. with exclude_from_trace():
  43. if i % 2:
  44. (x,) = apply(neg, x)
  45. (x,) = apply(neg, x)
  46. return x
  47. x = as_raw_tensor([1]).numpy()
  48. for i in range(3):
  49. y = f.__wrapped__(as_raw_tensor(x)).numpy()
  50. np.testing.assert_equal(f(as_raw_tensor(x)).numpy(), y)
  51. def test_print_in_trace():
  52. for symbolic in [False]: # cannot read value in symbolic mode
  53. @trace(symbolic=symbolic)
  54. def f(x):
  55. nonlocal buf
  56. neg = ops.Elemwise(Elemwise.Mode.NEGATE)
  57. (x,) = apply(neg, x)
  58. buf = x.numpy()
  59. (x,) = apply(neg, x)
  60. return x
  61. buf = None
  62. x = as_raw_tensor([1]).numpy()
  63. for i in range(3):
  64. y = f.__wrapped__(as_raw_tensor(x)).numpy()
  65. z = buf
  66. buf = None
  67. np.testing.assert_equal(f(as_raw_tensor(x)).numpy(), y)
  68. np.testing.assert_equal(z, buf)
  69. def test_dump():
  70. @trace(symbolic=True, capture_as_const=True)
  71. def f(a, b):
  72. op = ops.Elemwise(Elemwise.Mode.ADD)
  73. (y,) = apply(op, a, b)
  74. return y
  75. a = as_raw_tensor([2]).numpy()
  76. b = as_raw_tensor([4]).numpy()
  77. y = f.__wrapped__(as_raw_tensor(a), as_raw_tensor(b)).numpy()
  78. for i in range(3):
  79. np.testing.assert_equal(f(as_raw_tensor(a), as_raw_tensor(b)).numpy(), y)
  80. file = io.BytesIO()
  81. dump_info = f.dump(file)
  82. assert dump_info.nr_opr == 3
  83. np.testing.assert_equal(dump_info.inputs, ["arg_0", "arg_1"])
  84. np.testing.assert_equal(dump_info.outputs, ["ADD(arg_0,arg_1)[4]"])
  85. file.seek(0)
  86. result = cgtools.load_and_inference(file, [a, b])
  87. np.testing.assert_equal(result[0], y)
  88. def test_capture_dump():
  89. a = as_raw_tensor([2])
  90. @trace(symbolic=True, capture_as_const=True)
  91. def f(x):
  92. op = ops.Elemwise(Elemwise.Mode.MUL)
  93. (y,) = apply(op, x, a)
  94. return y
  95. x = as_raw_tensor([3]).numpy()
  96. y = f.__wrapped__(as_raw_tensor(x)).numpy()
  97. for i in range(3):
  98. np.testing.assert_equal(f(as_raw_tensor(x)).numpy(), y)
  99. file = io.BytesIO()
  100. f.dump(file)
  101. file.seek(0)
  102. result = cgtools.load_and_inference(file, [x])
  103. np.testing.assert_equal(result[0], y)
  104. def test_dump_volatile():
  105. p = as_raw_tensor([2])
  106. @trace(symbolic=True, capture_as_const=True)
  107. def f(x):
  108. op = ops.Elemwise(Elemwise.Mode.MUL)
  109. (y,) = apply(op, x, p)
  110. return y
  111. x = as_raw_tensor([3]).numpy()
  112. y = f.__wrapped__(as_raw_tensor(x)).numpy()
  113. for i in range(3):
  114. np.testing.assert_equal(f(as_raw_tensor(x)).numpy(), y)
  115. file = io.BytesIO()
  116. f.dump(file, optimize_for_inference=False)
  117. file.seek(0)
  118. cg, _, outputs = G.load_graph(file)
  119. (out,) = outputs
  120. assert (
  121. cgtools.get_owner_opr_type(cgtools.get_owner_opr_inputs(out)[1])
  122. == "ImmutableTensor"
  123. )
  124. def test_trace_profiler():
  125. for symbolic in [False, True]:
  126. @trace(symbolic=symbolic, profiling=True)
  127. def f(x):
  128. op = ops.Elemwise(Elemwise.Mode.NEGATE)
  129. (y,) = apply(op, x)
  130. return y
  131. x = as_raw_tensor([1]).numpy()
  132. y = f.__wrapped__(as_raw_tensor(x)).numpy()
  133. f(as_raw_tensor(x))
  134. f(as_raw_tensor(x)) # XXX: has to run twice
  135. out = f.get_profile()
  136. assert out.get("profiler")
  137. @pytest.mark.skip(reason="force opt_level=0 when building graph")
  138. def test_goptions():
  139. @trace(symbolic=True, opt_level=0, capture_as_const=True)
  140. def f(x):
  141. # directly return x / x will not trigger gopt
  142. # since there's no way to tell the two x are the same
  143. y = 2.0 * x
  144. return y / y
  145. @trace(symbolic=True, opt_level=1, capture_as_const=True)
  146. def g(x):
  147. y = 2.0 * x
  148. return y / y
  149. d = tensor(0.0)
  150. assert not np.isfinite(f(d).numpy())
  151. np.testing.assert_equal(g(d).numpy().item(), 1.0)
  152. @pytest.mark.skip(reason="force opt_level=0 when building graph")
  153. def test_goptions_log_sum_exp():
  154. @trace(symbolic=True, opt_level=0, capture_as_const=True)
  155. def f(x, y):
  156. return log(exp(x) + exp(y))
  157. @trace(symbolic=True, opt_level=1, capture_as_const=True)
  158. def g(x, y):
  159. return log(exp(x) + exp(y))
  160. val = 1.0e4
  161. d = tensor(val)
  162. o = tensor(0.0)
  163. assert not np.isfinite(f(d, o).numpy())
  164. np.testing.assert_almost_equal(g(d, o), val)
  165. @pytest.mark.skip(reason="could not use opt_level=0 with dump")
  166. def test_goptions_log_exp():
  167. @trace(symbolic=True, opt_level=0, capture_as_const=True)
  168. def f(x):
  169. return log(exp(x))
  170. @trace(symbolic=True, opt_level=1, capture_as_const=True)
  171. def g(x):
  172. return log(exp(x))
  173. f(tensor(1.0))
  174. _, out = mkstemp()
  175. f.dump(out, optimize_for_inference=False)
  176. *_, outputs = G.load_graph(out)
  177. oprs_1 = cgtools.get_oprs_seq(outputs)
  178. g(tensor(1.0))
  179. g.dump(out, optimize_for_inference=False)
  180. *_, outputs = G.load_graph(out)
  181. oprs_2 = cgtools.get_oprs_seq(outputs)
  182. assert len(oprs_1) - len(oprs_2) == 2
  183. def test_optimize_for_inference():
  184. @trace(symbolic=True, capture_as_const=True)
  185. def f(x):
  186. return exp(x)
  187. _, out = mkstemp()
  188. f(tensor(5.0))
  189. f.dump(out, enable_io16xc32=True)
  190. res = G.load_graph(out)
  191. computing_input = res.output_vars_list[0].owner.inputs[0]
  192. assert computing_input.dtype == np.float16
  193. def test_optimize_for_inference_broadcast():
  194. a = tensor(np.ones(1, dtype=np.float32))
  195. @trace(capture_as_const=True, symbolic_shape=True)
  196. def f():
  197. (b,) = apply(ops.Broadcast(), a, tensor([1, 10], dtype=np.int32))
  198. return b
  199. f()
  200. f.dump(io.BytesIO())
  201. def test_trace_cvt_bool():
  202. set_symbolic_shape(True)
  203. x = tensor([0], dtype=np.int32)
  204. @trace(symbolic=True)
  205. def f(x):
  206. return x.shape[0] == 0
  207. for i in range(3):
  208. np.testing.assert_equal(f(x).numpy()[0], False)
  209. def test_trace_reshape():
  210. for symbolic in [False, True]:
  211. set_symbolic_shape(True)
  212. x1 = tensor(np.random.randn(2, 10, 10))
  213. x2 = tensor(np.random.randn(4, 10, 10))
  214. x3 = tensor(np.random.randn(8, 10, 10))
  215. @trace(symbolic=symbolic, capture_as_const=True)
  216. def f(x):
  217. y = x.reshape(x.shape[0], 100)
  218. return y
  219. f(x1)
  220. f(x2)
  221. f(x3)
  222. def test_trace_topk():
  223. x = tensor([5, 2, 7, 1, 0, 3, 2])
  224. @trace(symbolic=True)
  225. def f(x):
  226. y = F.topk(x, 3)
  227. np.testing.assert_equal(y[0].shape.numpy(), np.array([3,]))
  228. return y
  229. for i in range(3):
  230. f(x)
  231. def test_trace_warp_perspective():
  232. inp_shape = (1, 1, 4, 4)
  233. x = tensor(np.arange(16, dtype=np.float32).reshape(inp_shape))
  234. M_shape = (1, 3, 3)
  235. M = tensor(
  236. np.array(
  237. [[1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [0.0, 0.0, 1.0]], dtype=np.float32
  238. ).reshape(M_shape)
  239. )
  240. @trace(symbolic=True)
  241. def f(x, M):
  242. out = F.warp_perspective(x, M, (2, 2))
  243. np.testing.assert_equal(out.shape.numpy(), np.array([1, 1, 2, 2]))
  244. return out
  245. for i in range(1):
  246. f(x, M)
  247. def test_raise_on_trace():
  248. step_count = 0
  249. catch_count = 0
  250. bad_step = 10
  251. class CatchMe(Exception):
  252. pass
  253. a = tensor([1, 2, 3, 4])
  254. b = tensor([5, 6, 7, 8])
  255. c = tensor([9, 0, 1, 2])
  256. @trace
  257. def add_abc(a, b, c):
  258. print("Hello")
  259. ps = a + b
  260. result = ps + c
  261. if step_count == bad_step:
  262. raise CatchMe("catch me")
  263. return result
  264. for i in range(100):
  265. try:
  266. d = add_abc(a, b, c)
  267. except CatchMe as e:
  268. catch_count += 1
  269. else:
  270. np.testing.assert_equal(d.numpy(), (a + b + c).numpy())
  271. step_count += 1
  272. assert catch_count == 1
  273. def test_trace_broadcast():
  274. for symbolic in [False, True]:
  275. set_symbolic_shape(True)
  276. x1 = tensor(np.random.randn(3, 1, 1))
  277. x2 = tensor(np.random.randn(1, 4, 1))
  278. x3 = tensor(np.random.randn(1, 1, 5))
  279. @trace(symbolic=symbolic, capture_as_const=True)
  280. def f(x):
  281. y = F.broadcast_to(x, (3, 4, 5))
  282. return y
  283. f(x1)
  284. f(x2)
  285. f(x3)
  286. def test_trace_nms():
  287. def make_inputs(n):
  288. boxes = np.zeros((n, 4))
  289. boxes[:, :2] = np.random.rand(n, 2) * 100
  290. boxes[:, 2:] = np.random.rand(n, 2) * 100 + 100
  291. scores = np.random.rand(n)
  292. return tensor(boxes), tensor(scores)
  293. @trace(symbolic=False)
  294. def f(boxes, scores):
  295. results = F.nn.nms(boxes, scores=scores, iou_thresh=0.5, max_output=20)
  296. with exclude_from_trace():
  297. _ = F.nn.nms(boxes, scores=scores, iou_thresh=0.5)
  298. return results
  299. f(*make_inputs(10))
  300. f(*make_inputs(20))
  301. f(*make_inputs(30))
  302. def test_trace_valid_broadcast():
  303. set_symbolic_shape(True)
  304. x1 = tensor(np.random.randn(1, 1))
  305. x2 = tensor(np.random.randn(1, 2))
  306. shape = (tensor([2]), tensor([2]))
  307. @trace(symbolic=False)
  308. def f(x, shape):
  309. y = F.broadcast_to(x, shape)
  310. return y
  311. f(x1, shape)
  312. f(x2, shape)
  313. def test_clip():
  314. x = tensor(np.random.randn(10, 10))
  315. @trace(symbolic=True)
  316. def f(x, lower, upper):
  317. y = F.clip(x, lower, upper)
  318. return y
  319. for i in range(3):
  320. f(x, tensor([0]), tensor([1]))
  321. # test returning noncontiguous tensor from trace
  322. def test_slice():
  323. @trace
  324. def f(x):
  325. return x[:, 1::2]
  326. x = F.arange(8).reshape(2, 4)
  327. f(x)
  328. y = f(x)
  329. np.testing.assert_array_equal(y.numpy(), x.numpy()[:, 1::2])
  330. y + y
  331. def test_random():
  332. def run_test(op):
  333. for symbolic_shape in [True, False]:
  334. @trace(symbolic=True, symbolic_shape=symbolic_shape)
  335. def f():
  336. out = op(size=[10, 10])
  337. out_shape = out.shape
  338. assert out_shape is not None
  339. if not isinstance(out_shape, tuple):
  340. assert out.shape.numpy() is not None
  341. return out
  342. for _ in range(3):
  343. f()
  344. run_test(uniform)
  345. run_test(normal)

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