tracer.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. # Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from paddle import _C_ops, _legacy_C_ops
  15. from paddle.base import core, framework
  16. name_mapping = {
  17. "graph_send_recv": {
  18. "final_op_name": "graph_send_recv",
  19. "x": "X",
  20. "src_index": "Src_index",
  21. "dst_index": "Dst_index",
  22. "out": "Out",
  23. "dst_count": "Dst_count",
  24. },
  25. "matmul_v2": {
  26. "final_op_name": "matmul",
  27. "transpose_x": "trans_x",
  28. "transpose_y": "trans_y",
  29. "x": "X",
  30. "y": "Y",
  31. "out": "Out",
  32. },
  33. # "elementwise_add": {
  34. # "final_op_name": "add",
  35. # "x": "X",
  36. # "y": "Y",
  37. # },
  38. "trunc": {
  39. "final_op_name": "trunc",
  40. "x": "X",
  41. "out": "Out",
  42. },
  43. # "pool2d": {
  44. # "final_op_name": "pool2d",
  45. # "x": "X",
  46. # "kernel_size": "ksize",
  47. # "out": "Out",
  48. # },
  49. "abs": {
  50. "final_op_name": "abs",
  51. "x": "X",
  52. "out": "Out",
  53. },
  54. "digamma": {
  55. "final_op_name": "digamma",
  56. "x": "X",
  57. "out": "Out",
  58. },
  59. "diagonal": {
  60. "final_op_name": "diagonal",
  61. "x": "Input",
  62. "offset": "offset",
  63. "axis1": "axis1",
  64. "axis2": "axis2",
  65. "out": "Out",
  66. },
  67. "roi_align": {
  68. "final_op_name": "roi_align",
  69. "x": "X",
  70. "boxes": "ROIs",
  71. "boxes_num": "RoisNum",
  72. "pooled_height": "pooled_height",
  73. "pooled_width": "pooled_width",
  74. "spatial_scale": "spatial_scale",
  75. "sampling_ratio": "sampling_ratio",
  76. "aligned": "aligned",
  77. },
  78. # "one_hot": {
  79. # "final_op_name": "one_hot",
  80. # "x": "X",
  81. # "num_class": "depth",
  82. # "out": "Out",
  83. # }
  84. }
  85. core_ops_args_info = _legacy_C_ops.get_core_ops_args_info()
  86. core_ops_args_type_info = _legacy_C_ops.get_core_ops_args_type_info()
  87. core_ops_returns_info = _legacy_C_ops.get_core_ops_returns_info()
  88. class Tracer(core.Tracer):
  89. """
  90. :api_attr: imperative
  91. Tracer is used to execute and record the operators executed, to construct the
  92. computation graph in dygraph model. Tracer has two mode, :code:`train_mode`
  93. and :code:`eval_mode`. In :code:`train_mode`, Tracer would add backward network
  94. automatically and perform AutoGrad by method :code:`loss.backward()`.
  95. In :code:`eval_mode`, Tracer would not add backward network.
  96. This is a low level API, users don't need to use it directly.
  97. """
  98. def __init__(self):
  99. super().__init__()
  100. self._train_mode = True
  101. def eager_legacy_trace_op(
  102. self,
  103. op_type,
  104. inputs,
  105. outputs,
  106. attrs,
  107. stop_gradient=False,
  108. inplace_map=None,
  109. ):
  110. function_ptr = _legacy_C_ops.__dict__[op_type]
  111. op_args = core_ops_args_info[op_type]
  112. op_args_type = core_ops_args_type_info[op_type]
  113. op_returns = core_ops_returns_info[op_type]
  114. arg_list = []
  115. for i in range(len(op_args)):
  116. # initialized with None
  117. arg_to_append = None
  118. arg_name = op_args[i]
  119. arg_type = op_args_type[i]
  120. if arg_name in inputs.keys():
  121. arg_to_append = inputs[arg_name]
  122. elif arg_name in outputs.keys():
  123. arg_to_append = outputs[arg_name]
  124. else:
  125. if "Num" in arg_name[-3:]:
  126. # Remove "Num" suffix to get out_name
  127. out_name = arg_name[:-3]
  128. assert out_name in outputs.keys()
  129. num_outs = len(outputs[out_name])
  130. arg_to_append = num_outs
  131. # NOTE(dev): For MasterParam/MasterParamOut in optimizer op
  132. elif "Var" in arg_name[-3:]:
  133. out_name = arg_name[:-3]
  134. print(out_name)
  135. if out_name in outputs.keys():
  136. arg_to_append = outputs[out_name]
  137. elif out_name in inputs.keys():
  138. arg_to_append = inputs[out_name]
  139. if arg_to_append is None:
  140. arg_list.append(arg_to_append)
  141. elif arg_type == "tensor":
  142. if isinstance(arg_to_append, list):
  143. arg_list.append(arg_to_append[0])
  144. else:
  145. arg_list.append(arg_to_append)
  146. elif arg_type == "list":
  147. assert isinstance(arg_to_append, list)
  148. arg_list.append(arg_to_append)
  149. else:
  150. assert arg_type == "int"
  151. assert isinstance(arg_to_append, int)
  152. arg_list.append(arg_to_append)
  153. attrs_list = []
  154. for k, v in attrs.items():
  155. attrs_list.append(k)
  156. attrs_list.append(v)
  157. returns = function_ptr(*arg_list, *attrs_list)
  158. if op_type == 'load_combine':
  159. assert len(outputs.keys()) == 1
  160. key = list(outputs.keys())[0]
  161. for j in range(len(returns)):
  162. returns[j]._share_underline_tensor_to(outputs[key][j])
  163. return
  164. if isinstance(returns, tuple):
  165. for i in range(len(op_returns)):
  166. retname = op_returns[i]
  167. if retname in outputs.keys():
  168. # Replaced outputs by function returns
  169. if isinstance(returns[i], list):
  170. for j in range(len(returns[i])):
  171. outputs[retname][j].reconstruct_from_(
  172. returns[i][j], False
  173. )
  174. else:
  175. if isinstance(outputs[retname], list):
  176. outputs[retname][0].reconstruct_from_(
  177. returns[i], False
  178. )
  179. else:
  180. outputs[retname].reconstruct_from_(
  181. returns[i], False
  182. )
  183. elif isinstance(returns, list):
  184. assert len(outputs.keys()) == 1
  185. key = list(outputs.keys())[0]
  186. for j in range(len(returns)):
  187. outputs[key][j].reconstruct_from_(returns[j], False)
  188. else:
  189. assert len(outputs.keys()) == 1
  190. key = list(outputs.keys())[0]
  191. if isinstance(outputs[key], list):
  192. outputs[key][0].reconstruct_from_(returns, False)
  193. else:
  194. outputs[key].reconstruct_from_(returns, False)
  195. def eager_trace_op(
  196. self,
  197. op_type,
  198. inputs,
  199. outputs,
  200. attrs,
  201. stop_gradient=False,
  202. inplace_map=None,
  203. ):
  204. assert op_type in name_mapping.keys()
  205. op_type = name_mapping[op_type]["final_op_name"]
  206. function_ptr = _C_ops.__dict__[op_type]
  207. core_ops_args_info = _C_ops.get_core_ops_args_info()
  208. core_ops_args_type_info = _C_ops.get_core_ops_args_type_info()
  209. core_ops_returns_info = _C_ops.get_core_ops_returns_info()
  210. op_args = core_ops_args_info[op_type]
  211. op_args_type = core_ops_args_type_info[op_type]
  212. op_returns = core_ops_returns_info[op_type]
  213. arg_list = []
  214. for i in range(len(op_args)):
  215. eager_arg_name = op_args[i]
  216. arg_type = op_args_type[i]
  217. assert eager_arg_name in name_mapping[op_type].keys()
  218. arg_name = name_mapping[op_type][eager_arg_name]
  219. if arg_name in inputs.keys():
  220. arg_to_append = inputs[arg_name]
  221. elif arg_name in outputs.keys():
  222. arg_to_append = outputs[arg_name]
  223. elif arg_name in attrs.keys() and arg_type == "":
  224. arg_to_append = attrs[arg_name]
  225. else:
  226. # dispensable
  227. arg_to_append = None
  228. if arg_type == "":
  229. # attribute
  230. arg_list.append(arg_to_append)
  231. elif arg_type == "tensor":
  232. if isinstance(arg_to_append, list):
  233. arg_list.append(arg_to_append[0])
  234. else:
  235. arg_list.append(arg_to_append)
  236. elif arg_type == "list":
  237. assert isinstance(arg_to_append, list)
  238. arg_list.append(arg_to_append)
  239. else:
  240. assert arg_to_append is None
  241. arg_list.append(arg_to_append)
  242. returns = function_ptr(*arg_list)
  243. if isinstance(returns, tuple):
  244. for i in range(len(op_returns)):
  245. eager_retname = op_returns[i]
  246. assert eager_retname in name_mapping[op_type].keys()
  247. retname = name_mapping[op_type][eager_retname]
  248. if retname in outputs.keys():
  249. # Replaced outputs by function returns
  250. if isinstance(returns[i], list):
  251. for j in range(len(returns[i])):
  252. outputs[retname][j].reconstruct_from_(
  253. returns[i][j], False
  254. )
  255. else:
  256. outputs[retname][0].reconstruct_from_(returns[i], False)
  257. elif isinstance(returns, list):
  258. assert len(outputs.keys()) == 1
  259. key = list(outputs.keys())[0]
  260. for j in range(len(returns)):
  261. outputs[key][j].reconstruct_from_(returns[j], False)
  262. else:
  263. assert len(outputs.keys()) == 1
  264. key = list(outputs.keys())[0]
  265. if isinstance(outputs[key], list):
  266. outputs[key][0].reconstruct_from_(returns, False)
  267. else:
  268. outputs[key].reconstruct_from_(returns, False)
  269. def trace_op(
  270. self,
  271. type,
  272. inputs,
  273. outputs,
  274. attrs,
  275. stop_gradient=False,
  276. inplace_map=None,
  277. ):
  278. if framework.in_dygraph_mode():
  279. # inputs : {"sum": [tensor], ...}
  280. # outputs : {"sum": [tensor], ...}
  281. if type in name_mapping.keys():
  282. type = name_mapping[type]["final_op_name"]
  283. assert type in _legacy_C_ops.__dict__
  284. self.eager_trace_op(
  285. type, inputs, outputs, attrs, stop_gradient, inplace_map
  286. )
  287. else:
  288. self.eager_legacy_trace_op(
  289. type, inputs, outputs, attrs, stop_gradient, inplace_map
  290. )
  291. else:
  292. raise ValueError("trace_op only work in dygraph mode")
  293. def train_mode(self):
  294. self._train_mode = True
  295. def eval_mode(self):
  296. self._train_mode = False