docc-pytorch 0.8.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ from docc.benchmarks.rtl import try_ensure_instrumentation_ready
2
+
3
+ # Ready the counter backends (e.g. ROCm) early: they must initialize before the
4
+ # workload sets up its own runtime. Best-effort so importing docc never fails when
5
+ # instrumentation is not configured.
6
+ try_ensure_instrumentation_ready()
7
+
8
+ from docc.pytorch.pytorch_program import PyTorchProgram
9
+ from docc.pytorch.graph_parser import GraphParser
@@ -0,0 +1,398 @@
1
+ """PyTorch GraphModule Parser
2
+
3
+ This module contains the PyTorch GraphModule Parser.
4
+ """
5
+
6
+ import numpy as np
7
+ import torch
8
+ import torch.export
9
+ import torch.fx
10
+ import torch.utils._pytree
11
+ import torch._functorch._aot_autograd.descriptors
12
+ from torch.fx.node import Argument
13
+
14
+ from typing import Any
15
+ from typing_extensions import Buffer
16
+
17
+ from docc.sdfg import (
18
+ StructuredSDFGBuilder,
19
+ StructuredSDFG,
20
+ Type,
21
+ Tensor,
22
+ Scalar,
23
+ Pointer,
24
+ DebugInfo,
25
+ Block,
26
+ ConstantNode,
27
+ AccessNode,
28
+ Tasklet,
29
+ TaskletCode,
30
+ )
31
+
32
+ from docc.pytorch.graph_parser.utils import (
33
+ TensorName,
34
+ ContainerMemory,
35
+ TensorInfo,
36
+ ContainerInfo,
37
+ TensorMetadata,
38
+ GraphParserError,
39
+ GraphParserBase,
40
+ get_node_target_name,
41
+ dispatch_to_module,
42
+ )
43
+
44
+ import docc.pytorch.graph_parser.blas
45
+ import docc.pytorch.graph_parser.builtin
46
+ import docc.pytorch.graph_parser.convolution
47
+ import docc.pytorch.graph_parser.creation
48
+ import docc.pytorch.graph_parser.elementwise
49
+ import docc.pytorch.graph_parser.nonlinear_activation
50
+ import docc.pytorch.graph_parser.normalization
51
+ import docc.pytorch.graph_parser.padding
52
+ import docc.pytorch.graph_parser.pooling
53
+ import docc.pytorch.graph_parser.reduction
54
+ import docc.pytorch.graph_parser.reshaping
55
+ import docc.pytorch.graph_parser.sparse
56
+ import docc.pytorch.graph_parser.tensor
57
+ import docc.pytorch.graph_parser.vision
58
+
59
+
60
+ class GraphParser(GraphParserBase):
61
+ """
62
+ This is the main PyTorch GraphModule Parser class. It creates a structured SDFG from a
63
+ GraphModule obtained after calling torch.export and its example inputs. It dispatches to the
64
+ GraphParser modules for parsing individual operations.
65
+ """
66
+
67
+ def __init__(
68
+ self,
69
+ name: str,
70
+ ep: torch.export.ExportedProgram,
71
+ example_input: tuple[Any, ...],
72
+ ):
73
+ """
74
+ Intialization with the GraphModule after calling torch.export and the example inputs.
75
+ """
76
+ super().__init__()
77
+
78
+ self.name: str = name
79
+ self.ep: torch.export.ExportedProgram = ep
80
+ self.example_input: tuple[Any, ...] = example_input
81
+
82
+ self.builder: StructuredSDFGBuilder = StructuredSDFGBuilder("__docc_" + name)
83
+ self._arguments: list[Any] = []
84
+
85
+ self.metadata: TensorMetadata = TensorMetadata()
86
+ self.result_copy: dict[TensorName, TensorName] = {}
87
+
88
+ def flatten_arg(self, arg: Argument) -> list[torch.fx.Node]:
89
+ """
90
+ Flattens a nested tuple/list to a list of torch.fx.Node's.
91
+ Example: ((arg_0, arg_1), arg_2) -> ["arg_0", "arg_1", "arg_2"]
92
+ """
93
+ result: list[torch.fx.Node] = []
94
+ if isinstance(arg, (tuple, list)):
95
+ for elem in arg:
96
+ result: list[torch.fx.Node] = result + self.flatten_arg(elem)
97
+ elif isinstance(arg, torch.fx.Node):
98
+ result.append(arg)
99
+ return result
100
+
101
+ def get_tensors_from_arg(self, arg: Argument) -> list[TensorName]:
102
+ """
103
+ Returns a list of all tensor names form an argument. Recursively calls itself for lists and
104
+ tuples.
105
+ """
106
+ return [node.name for node in self.flatten_arg(arg)]
107
+
108
+ def parse(self) -> None:
109
+ """
110
+ Parses the GraphModule (exported program) to a structured SDFG. This is done in two steps.
111
+ The first step is the pre-parsing step, in which all tensor information are collected and
112
+ written to the tensor metadata. Except for input and output arguments those tensors do not
113
+ have an underlying container yet.
114
+ The second step is the parsing step, in which all operations are actually translated to SDFG
115
+ operations. Containers are conservatively create along the way and also stored in the tensor
116
+ metadata. At the end all allocated memory is freed.
117
+ """
118
+ nodes = self.ep.graph_module.graph.nodes
119
+
120
+ # Collect all outputs for out args
121
+ for node in nodes:
122
+ if node.op == "placeholder":
123
+ self.parse_placeholder(node)
124
+ elif node.op == "call_function":
125
+ if get_node_target_name(node.target) in (
126
+ "aten._assert_tensor_metadata.default",
127
+ ):
128
+ continue # Skip output-less ops
129
+
130
+ sdfg_tensors: tuple[Tensor | None, ...] = self.get_node_sdfg_tensors(
131
+ node
132
+ )
133
+ deps: list[TensorName] = self.get_tensors_from_arg(node.args)
134
+ if len(sdfg_tensors) == 1:
135
+ self.metadata.add_tensor(
136
+ node.name, TensorInfo(node.name, sdfg_tensors[0])
137
+ )
138
+ for dep in deps:
139
+ self.metadata.add_dependency(node.name, dep)
140
+ else:
141
+ contained_names: list[TensorName] = []
142
+ for i in range(len(sdfg_tensors)):
143
+ tensor_name: TensorName = f"{node.name}_{i}"
144
+ contained_names.append(tensor_name)
145
+ self.metadata.add_tensor(
146
+ tensor_name, TensorInfo(tensor_name, sdfg_tensors[i])
147
+ )
148
+ for dep in deps:
149
+ self.metadata.add_dependency(tensor_name, dep)
150
+ self.metadata.add_tensor_tuple(node.name, contained_names)
151
+ elif node.op == "output":
152
+ output_nodes: list[torch.fx.Node] = self.flatten_arg(node.args)
153
+ for output_node in output_nodes:
154
+ if not output_node.name in self.ep.graph_signature.user_outputs:
155
+ continue
156
+
157
+ sdfg_type: Type = self.get_node_sdfg_type(output_node)
158
+ out_name: str = output_node.name
159
+ # FX names like "sin" would shadow C math functions in generated code.
160
+ out_container: str = f"__daisy__{out_name}"
161
+
162
+ if self.metadata.has_container(
163
+ out_name
164
+ ) or self.metadata.has_container(out_container):
165
+ continue
166
+
167
+ if not self.metadata.tensor(out_name).is_tight() or isinstance(
168
+ sdfg_type, Scalar
169
+ ):
170
+ if not isinstance(sdfg_type, Pointer):
171
+ sdfg_type: Type = Pointer(sdfg_type)
172
+ new_out_name: str = f"{out_name}_out"
173
+ self.builder.add_container(
174
+ new_out_name, sdfg_type, is_argument=True
175
+ )
176
+ self.metadata.add_container(
177
+ new_out_name,
178
+ ContainerInfo(
179
+ new_out_name, sdfg_type, ContainerMemory.OUT_ARGUMENT
180
+ ),
181
+ )
182
+ out_shape: list[str] = self.metadata.tensor(out_name).shape()
183
+ if len(out_shape) == 0:
184
+ out_shape: list[str] = ["1"]
185
+ new_out_tensor: Tensor = Tensor(
186
+ self.metadata.tensor(out_name).element_type(),
187
+ out_shape,
188
+ )
189
+ self.metadata.add_tensor(
190
+ new_out_name,
191
+ TensorInfo(new_out_name, new_out_tensor, new_out_name),
192
+ )
193
+ self.metadata.add_dependency(new_out_name, out_name)
194
+ self.result_copy[out_name] = new_out_name
195
+ else:
196
+ self.builder.add_container(
197
+ out_container, sdfg_type, is_argument=True
198
+ )
199
+ self.metadata.add_container(
200
+ out_container,
201
+ ContainerInfo(
202
+ out_container, sdfg_type, ContainerMemory.OUT_ARGUMENT
203
+ ),
204
+ )
205
+ self.metadata.tensor(out_name).set_container(out_container)
206
+
207
+ for node in nodes:
208
+ if node.op == "placeholder":
209
+ self.metadata.live(self.metadata.tensor(node.name).container())
210
+ elif node.op == "call_function":
211
+ pass
212
+ dispatch_to_module(
213
+ node,
214
+ self.builder,
215
+ self.metadata,
216
+ )
217
+ elif node.op == "output":
218
+ self.parse_output(node)
219
+ else:
220
+ raise GraphParserError(self, node, "Unknown op kind: " + node.op)
221
+
222
+ for name in self.metadata.containers_memory_managed():
223
+ if isinstance(self.metadata.container(name).sdfg_type(), Pointer):
224
+ self.builder.add_free_block(name)
225
+ self.metadata.dead(name)
226
+
227
+ def parse_placeholder(self, node: torch.fx.Node) -> None:
228
+ """
229
+ Parses a PyTorch placeholder operation by creating a tensor information, a container
230
+ information and, an actual SDFG container for it. Notice, that all arguments of an SDFG must
231
+ have C-strides. This is also ensured here.
232
+ """
233
+ if not "desc" in node.meta:
234
+ raise GraphParserError(self, node, "Missing desc metadata in placeholder")
235
+ desc: Any = node.meta["desc"]
236
+ if isinstance(desc, torch._functorch._aot_autograd.descriptors.PlainAOTInput):
237
+ # Normal argument
238
+ if desc.idx >= len(self.example_input):
239
+ raise GraphParserError(
240
+ self,
241
+ node,
242
+ f"No example input for placeholder {desc.idx}",
243
+ )
244
+ sdfg_type: Type = self.determine_sdfg_type(
245
+ node, self.example_input[desc.idx]
246
+ )
247
+ sdfg_tensor: Tensor | None = self.determine_sdfg_tensor_type(
248
+ node, self.example_input[desc.idx]
249
+ )
250
+ self._arguments.append(self.example_input[desc.idx])
251
+
252
+ self.builder.add_container(node.name, sdfg_type, is_argument=True)
253
+ self.metadata.add_container(
254
+ node.name,
255
+ ContainerInfo(node.name, sdfg_type, ContainerMemory.IN_ARGUMENT),
256
+ )
257
+
258
+ # The call always provides a tensor with C-strides. If the tensor has non C-strides we
259
+ # enforce them here.
260
+ if sdfg_tensor is None:
261
+ contiguous_tensor: Tensor | None = None
262
+ else:
263
+ contiguous_tensor: Tensor | None = Tensor(
264
+ sdfg_tensor.element_type, sdfg_tensor.shape
265
+ )
266
+ self.metadata.add_tensor(
267
+ node.name, TensorInfo(node.name, contiguous_tensor, node.name)
268
+ )
269
+ elif isinstance(
270
+ desc, torch._functorch._aot_autograd.descriptors.BufferAOTInput
271
+ ):
272
+ # Constant argument
273
+ sdfg_type: Type = self.get_node_sdfg_type(node)
274
+ sdfg_tensor: Tensor | None = self.get_node_sdfg_tensor(node)
275
+ if sdfg_tensor is None:
276
+ raise GraphParserError(self, node, "Could not get SDFG tensor type")
277
+
278
+ self.builder.add_container(node.name, sdfg_type)
279
+ self.metadata.add_container(
280
+ node.name,
281
+ ContainerInfo(node.name, sdfg_type, ContainerMemory.UNMANAGED),
282
+ )
283
+ self.metadata.add_tensor(
284
+ node.name, TensorInfo(node.name, sdfg_tensor, node.name)
285
+ )
286
+
287
+ if desc.target not in self.ep.constants:
288
+ raise GraphParserError(
289
+ self,
290
+ node,
291
+ "Encountered constant argument that is not present in the constants dictionary: "
292
+ + desc.target,
293
+ )
294
+ from torch.fx._symbolic_trace import _ConstantAttributeType
295
+
296
+ constant: _ConstantAttributeType = self.ep.constants[desc.target]
297
+ if not isinstance(constant, torch.Tensor):
298
+ raise GraphParserError(
299
+ self,
300
+ node,
301
+ "Expected constant to be torch.Tensor type but got: "
302
+ + str(type(constant)),
303
+ )
304
+
305
+ debug_info: DebugInfo = self.get_debug_info(node)
306
+ if constant.shape in (torch.Size([]), torch.Size([1])):
307
+ # A single-value constant
308
+ block: Block = self.builder.add_block(debug_info)
309
+ const_access: ConstantNode = self.builder.add_constant(
310
+ block, str(constant.item()), sdfg_tensor.element_type, debug_info
311
+ )
312
+ output_access: AccessNode = self.builder.add_access(
313
+ block, node.name, debug_info
314
+ )
315
+ tasklet: Tasklet = self.builder.add_tasklet(
316
+ block, TaskletCode.assign, ["_in"], ["_out"], debug_info
317
+ )
318
+ self.builder.add_memlet(
319
+ block, const_access, "void", tasklet, "_in", debug_info=debug_info
320
+ )
321
+ self.builder.add_memlet(
322
+ block,
323
+ tasklet,
324
+ "_out",
325
+ output_access,
326
+ "void",
327
+ subset="" if isinstance(sdfg_type, Scalar) else "0",
328
+ debug_info=debug_info,
329
+ )
330
+ else:
331
+ # Multi-value constant
332
+ constant_arr: np.ndarray = constant.detach().cpu().contiguous().numpy()
333
+ constant_raw: Buffer = constant_arr.reshape(-1).view(np.uint8) # type: ignore
334
+
335
+ self.builder.add_load_const_op(
336
+ node.name, sdfg_type, constant_raw, debug_info
337
+ )
338
+ else:
339
+ raise GraphParserError(
340
+ self, node, "Unsupported desc metadata type: " + str(desc)
341
+ )
342
+
343
+ def parse_output(self, node: torch.fx.Node) -> None:
344
+ """
345
+ Parses a PyTorch output operation by setting the SDFG metadata about output arguments and
346
+ their shape information.
347
+ """
348
+ outputs: list[TensorName] = self.get_tensors_from_arg(node.args)
349
+ non_user_outputs: list[int] = []
350
+ for i in range(len(outputs)):
351
+ output: TensorName = outputs[i]
352
+ if not output in self.ep.graph_signature.user_outputs:
353
+ non_user_outputs.append(i)
354
+ continue
355
+
356
+ if output in self.result_copy:
357
+ new_output: TensorName = self.result_copy[output]
358
+ output_info: TensorInfo = self.metadata.tensor(output)
359
+ new_output_info: TensorInfo = self.metadata.tensor(new_output)
360
+ self.copy_output_tensor(
361
+ node, self.builder, self.metadata, output_info, new_output_info
362
+ )
363
+ outputs[i] = new_output
364
+
365
+ for non_user_output in non_user_outputs:
366
+ del outputs[non_user_output]
367
+
368
+ output_containers: list[str] = [
369
+ self.metadata.tensor(output).container() for output in outputs
370
+ ]
371
+ self.builder.add_metadata("output_args", ",".join(output_containers))
372
+ for output, output_container in zip(outputs, output_containers):
373
+ self.builder.add_metadata(
374
+ f"{output_container}_shape",
375
+ self.metadata.tensor(output).shape_str(),
376
+ )
377
+
378
+ # Preserve the original PyTorch output structure (nested tuples, dicts,
379
+ # dataclasses, single tensor, None leaves, ...) as a serialized pytree
380
+ # spec. At runtime the flat outputs produced by the compiled artifact are
381
+ # reassembled with this spec so the returned structure matches eager
382
+ # PyTorch exactly.
383
+ out_spec: torch.utils._pytree.TreeSpec | None = self.ep.call_spec.out_spec
384
+ if out_spec is not None:
385
+ self.builder.add_metadata(
386
+ "output_pytree_spec", torch.utils._pytree.treespec_dumps(out_spec)
387
+ )
388
+ self.builder.add_metadata("output_num_leaves", str(out_spec.num_leaves))
389
+
390
+ def to_sdfg(self) -> StructuredSDFG:
391
+ """
392
+ Detaches the structured SDFG from the internal structured SDFG builder and returns it.
393
+ """
394
+ return self.builder.move()
395
+
396
+ def get_arguments(self) -> tuple[Any, ...]:
397
+ """Return all the arguments"""
398
+ return tuple(self._arguments)
@@ -0,0 +1,193 @@
1
+ """
2
+ GraphParser modules for parsing BLAS and LAPACK operations.
3
+ """
4
+
5
+ import torch.fx
6
+ from torch.fx.node import Argument
7
+
8
+ from docc.sdfg import StructuredSDFGBuilder, Tensor, DebugInfo
9
+
10
+ from docc.pytorch.graph_parser.utils import (
11
+ TensorInfo,
12
+ TensorConstant,
13
+ TensorMetadata,
14
+ GraphParserError,
15
+ GraphParserModule,
16
+ register_module,
17
+ )
18
+
19
+
20
+ class MMParser(GraphParserModule):
21
+ """Formula is: result = self @ mat2"""
22
+
23
+ def parse(
24
+ self,
25
+ node: torch.fx.Node,
26
+ builder: StructuredSDFGBuilder,
27
+ metadata: TensorMetadata,
28
+ ) -> None:
29
+ if len(node.args) != 2:
30
+ raise GraphParserError(
31
+ self,
32
+ node,
33
+ "Expected exactly 2 arguments but got " + str(len(node.args)),
34
+ )
35
+ if len(node.kwargs) != 0:
36
+ raise GraphParserError(
37
+ self, node, "Unsupported kwargs: " + str(node.kwargs)
38
+ )
39
+ self_info: TensorInfo = self.get_arg_tensor_info(node, metadata, 0)
40
+ mat2_info: TensorInfo = self.get_arg_tensor_info(node, metadata, 1)
41
+ result_info: TensorInfo = self.get_result_tensor_info(node, builder, metadata)
42
+ debug_info: DebugInfo = self.get_debug_info(node)
43
+ builder.add_matmul_op(
44
+ self_info.container(),
45
+ self_info.sdfg_tensor_type(),
46
+ mat2_info.container(),
47
+ mat2_info.sdfg_tensor_type(),
48
+ result_info.container(),
49
+ result_info.sdfg_tensor_type(),
50
+ debug_info,
51
+ )
52
+
53
+
54
+ register_module("aten.mm.default", MMParser())
55
+ register_module("aten.bmm.default", MMParser())
56
+
57
+
58
+ class AddMMParser(GraphParserModule):
59
+ """Formula is: result = beta * self + alpha * (mat1 @ mat2)"""
60
+
61
+ def parse(
62
+ self,
63
+ node: torch.fx.Node,
64
+ builder: StructuredSDFGBuilder,
65
+ metadata: TensorMetadata,
66
+ ) -> None:
67
+ if len(node.args) != 3:
68
+ raise GraphParserError(
69
+ self,
70
+ node,
71
+ "Expected exactly 3 arguments but got " + str(len(node.args)),
72
+ )
73
+ alpha_arg: Argument = None
74
+ beta_arg: Argument = None
75
+ for key in node.kwargs:
76
+ if key == "alpha":
77
+ alpha_arg: Argument = node.kwargs[key]
78
+ elif key == "beta":
79
+ beta_arg: Argument = node.kwargs[key]
80
+ else:
81
+ raise GraphParserError(
82
+ self, node, "Unsupported kwargs: " + str(node.kwargs)
83
+ )
84
+
85
+ self_info: TensorInfo = self.get_arg_tensor_info(node, metadata, 0)
86
+ mat1_info: TensorInfo = self.get_arg_tensor_info(node, metadata, 1)
87
+ mat2_info: TensorInfo = self.get_arg_tensor_info(node, metadata, 2)
88
+ result_info: TensorInfo = self.get_result_tensor_info(node, builder, metadata)
89
+ debug_info: DebugInfo = self.get_debug_info(node)
90
+
91
+ # matmul = mat1 @ mat2
92
+ matmul_info: TensorInfo = self.create_intermediate_tensor_info(
93
+ node,
94
+ builder,
95
+ metadata,
96
+ result_info.sdfg_type(),
97
+ result_info.sdfg_tensor_type(),
98
+ [mat1_info, mat2_info],
99
+ )
100
+ builder.add_matmul_op(
101
+ mat1_info.container(),
102
+ mat1_info.sdfg_tensor_type(),
103
+ mat2_info.container(),
104
+ mat2_info.sdfg_tensor_type(),
105
+ matmul_info.container(),
106
+ matmul_info.sdfg_tensor_type(),
107
+ debug_info,
108
+ )
109
+
110
+ # mul1 = alpha * matmul
111
+ if alpha_arg is None:
112
+ mul1_info: TensorInfo = matmul_info
113
+ else:
114
+ alpha_info_or_const: TensorInfo | TensorConstant = (
115
+ self.convert_arg_to_tensor_info_or_constant(
116
+ node,
117
+ metadata,
118
+ alpha_arg,
119
+ align_constant_type=matmul_info.element_type(),
120
+ )
121
+ )
122
+ mul1_info: TensorInfo = self.create_intermediate_tensor_info(
123
+ node,
124
+ builder,
125
+ metadata,
126
+ matmul_info.sdfg_type(),
127
+ matmul_info.sdfg_tensor_type(),
128
+ [alpha_info_or_const, matmul_info],
129
+ )
130
+ builder.add_elementwise_op(
131
+ "mul",
132
+ alpha_info_or_const.container(),
133
+ alpha_info_or_const.sdfg_tensor_type(),
134
+ matmul_info.container(),
135
+ matmul_info.sdfg_tensor_type(),
136
+ mul1_info.container(),
137
+ mul1_info.sdfg_tensor_type(),
138
+ debug_info,
139
+ )
140
+
141
+ # mul2 = beta * self
142
+ if beta_arg is None:
143
+ mul2_info: TensorInfo = self_info
144
+ else:
145
+ beta_info_or_const: TensorInfo | TensorConstant = (
146
+ self.convert_arg_to_tensor_info_or_constant(
147
+ node,
148
+ metadata,
149
+ beta_arg,
150
+ align_constant_type=self_info.element_type(),
151
+ )
152
+ )
153
+ mul2_info: TensorInfo = self.create_intermediate_tensor_info(
154
+ node,
155
+ builder,
156
+ metadata,
157
+ self_info.sdfg_type(),
158
+ self_info.sdfg_tensor_type(),
159
+ [beta_info_or_const, self_info],
160
+ )
161
+ builder.add_elementwise_op(
162
+ "mul",
163
+ beta_info_or_const.container(),
164
+ beta_info_or_const.sdfg_tensor_type(),
165
+ self_info.container(),
166
+ self_info.sdfg_tensor_type(),
167
+ mul2_info.container(),
168
+ mul2_info.sdfg_tensor_type(),
169
+ debug_info,
170
+ )
171
+
172
+ # Broadcast mul2 shape to mul1 shape if needed
173
+ mul1_tensor: Tensor = mul1_info.sdfg_tensor_type()
174
+ mul2_tensor: Tensor = mul2_info.sdfg_tensor_type()
175
+ if len(mul1_info.shape()) != len(mul2_info.shape()):
176
+ mul1_tensor, mul2_tensor = self.align_elementwise_tensors(
177
+ node, mul1_tensor, mul2_tensor
178
+ )
179
+
180
+ # result = mul2 + mul1
181
+ builder.add_elementwise_op(
182
+ "add",
183
+ mul2_info.container(),
184
+ mul2_tensor,
185
+ mul1_info.container(),
186
+ mul1_tensor,
187
+ result_info.container(),
188
+ result_info.sdfg_tensor_type(),
189
+ debug_info,
190
+ )
191
+
192
+
193
+ register_module("aten.addmm.default", AddMMParser())
@@ -0,0 +1,61 @@
1
+ """
2
+ GraphParser modules for parsing builtin Python functions.
3
+ """
4
+
5
+ import torch.fx
6
+ from torch.fx.node import Argument
7
+
8
+ from docc.sdfg import StructuredSDFGBuilder
9
+
10
+ from docc.pytorch.graph_parser.utils import (
11
+ TensorName,
12
+ TensorMetadata,
13
+ GraphParserError,
14
+ GraphParserModule,
15
+ register_module,
16
+ )
17
+
18
+
19
+ class GetitemParser(GraphParserModule):
20
+ def parse(
21
+ self,
22
+ node: torch.fx.Node,
23
+ builder: StructuredSDFGBuilder,
24
+ metadata: TensorMetadata,
25
+ ) -> None:
26
+ if len(node.args) != 2:
27
+ raise GraphParserError(
28
+ self,
29
+ node,
30
+ "Expected exactly 2 arguments but got " + str(len(node.args)),
31
+ )
32
+ if len(node.kwargs) != 0:
33
+ raise GraphParserError(
34
+ self, node, "Unsupported kwargs: " + str(node.kwargs)
35
+ )
36
+
37
+ first: Argument = node.args[0]
38
+ second: Argument = node.args[1]
39
+ if not isinstance(first, torch.fx.Node):
40
+ raise GraphParserError(
41
+ self,
42
+ node,
43
+ "Expected first argument to be forch.fx.Node type but got: "
44
+ + str(type(first)),
45
+ )
46
+ if not isinstance(second, int):
47
+ raise GraphParserError(
48
+ self,
49
+ node,
50
+ "Expected second argument to be int type but got: " + str(type(second)),
51
+ )
52
+
53
+ ref_name: TensorName = f"{first.name}_{second}"
54
+ if not metadata.has_tensor(ref_name):
55
+ raise GraphParserError(
56
+ self, node, f"Could not find tensor information for '{ref_name}'"
57
+ )
58
+ self.create_result_view(node, builder, metadata, metadata.tensor(ref_name))
59
+
60
+
61
+ register_module("_operator.getitem", GetitemParser())