nnschemaparser 0.1.0__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.
- nnschemaparser/__init__.py +27 -0
- nnschemaparser/core/__init__.py +16 -0
- nnschemaparser/core/container_keys.py +69 -0
- nnschemaparser/core/instructions.py +399 -0
- nnschemaparser/core/model_schema.py +94 -0
- nnschemaparser/core/tensor_schema.py +55 -0
- nnschemaparser/dump.py +487 -0
- nnschemaparser/forward.py +29 -0
- nnschemaparser/interpreter/__init__.py +19 -0
- nnschemaparser/interpreter/control_flow.py +570 -0
- nnschemaparser/interpreter/execution.py +767 -0
- nnschemaparser/interpreter/interpreter.py +338 -0
- nnschemaparser/interpreter/scope.py +121 -0
- nnschemaparser/interpreter/tracer.py +346 -0
- nnschemaparser/parser/__init__.py +14 -0
- nnschemaparser/parser/children.py +171 -0
- nnschemaparser/parser/lowering/__init__.py +16 -0
- nnschemaparser/parser/lowering/base.py +354 -0
- nnschemaparser/parser/lowering/block_calls.py +350 -0
- nnschemaparser/parser/lowering/body.py +37 -0
- nnschemaparser/parser/lowering/calls.py +689 -0
- nnschemaparser/parser/lowering/control_flow.py +519 -0
- nnschemaparser/parser/lowering/effects.py +164 -0
- nnschemaparser/parser/lowering/errors.py +24 -0
- nnschemaparser/parser/lowering/expressions.py +805 -0
- nnschemaparser/parser/lowering/naming.py +179 -0
- nnschemaparser/parser/lowering/operators.py +333 -0
- nnschemaparser/parser/lowering/runtime_ops.py +260 -0
- nnschemaparser/parser/lowering/statements.py +600 -0
- nnschemaparser/parser/lowering/values.py +97 -0
- nnschemaparser/parser/parser.py +599 -0
- nnschemaparser/parser/resolution.py +280 -0
- nnschemaparser/py.typed +0 -0
- nnschemaparser-0.1.0.dist-info/METADATA +200 -0
- nnschemaparser-0.1.0.dist-info/RECORD +38 -0
- nnschemaparser-0.1.0.dist-info/WHEEL +5 -0
- nnschemaparser-0.1.0.dist-info/licenses/LICENSE +21 -0
- nnschemaparser-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NNSchemaParser.
|
|
3
|
+
|
|
4
|
+
Converts a torch nn.Module into an inspectable ModelBlockSchema graph that
|
|
5
|
+
keeps the original variable names of the forward source and every sub-module,
|
|
6
|
+
and executes it with a schema interpreter re-dispatching to the real torch
|
|
7
|
+
callables.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Import Modules
|
|
11
|
+
from nnschemaparser.core import ModelBlockSchema, TensorRepr, TensorReprWithValue
|
|
12
|
+
from nnschemaparser.dump import dump_schema
|
|
13
|
+
from nnschemaparser.interpreter import SchemaInterpreter, TraceListener, TraceRecorder
|
|
14
|
+
from nnschemaparser.parser import NNParser
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"ModelBlockSchema",
|
|
18
|
+
"TraceListener",
|
|
19
|
+
"TraceRecorder",
|
|
20
|
+
"dump_schema",
|
|
21
|
+
"NNParser",
|
|
22
|
+
"SchemaInterpreter",
|
|
23
|
+
"TensorRepr",
|
|
24
|
+
"TensorReprWithValue"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
__version__: str = "0.1.0"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core data model of NNSchemaParser.
|
|
3
|
+
|
|
4
|
+
The schema types describing a parsed model: the block schema tree, the tensor
|
|
5
|
+
representations and the instruction types of the block bodies.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Import Modules
|
|
9
|
+
from nnschemaparser.core.model_schema import ModelBlockSchema
|
|
10
|
+
from nnschemaparser.core.tensor_schema import TensorRepr, TensorReprWithValue
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ModelBlockSchema",
|
|
14
|
+
"TensorRepr",
|
|
15
|
+
"TensorReprWithValue"
|
|
16
|
+
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Container entry key utilities shared by the lowering and the interpreter.
|
|
3
|
+
|
|
4
|
+
The entries of a sub-block container are keyed by "container.index" in the
|
|
5
|
+
sub-block dictionaries, and must be iterated in their declaration order.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Import Modules
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def container_entry_sort_key(entry_key: str) -> int:
|
|
12
|
+
"""
|
|
13
|
+
Get the numeric sort key of a container entry key.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
entry_key (str): The entry key (e.g. "encoders.2").
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
int: The numeric suffix of the key, or -1 when not numeric.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
# Split the key into its container prefix and its suffix
|
|
23
|
+
parts: list[str] = entry_key.rsplit(".", 1)
|
|
24
|
+
|
|
25
|
+
# A numeric suffix is sorted by its value
|
|
26
|
+
if len(parts) == 2 and parts[1].isdigit():
|
|
27
|
+
return int(parts[1])
|
|
28
|
+
|
|
29
|
+
# A non numeric suffix is sorted last
|
|
30
|
+
return -1
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def container_entry_keys(
|
|
34
|
+
sub_block_names: set[str] | dict[str, str],
|
|
35
|
+
container_name: str
|
|
36
|
+
) -> list[str]:
|
|
37
|
+
"""
|
|
38
|
+
Get the ordered entry keys of a container in the parsed sub-blocks.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
sub_block_names (set[str] | dict[str, str]): The names of the parsed
|
|
42
|
+
sub-blocks, either a set of names or the sub-block dictionary.
|
|
43
|
+
container_name (str): The name of the container.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
list[str]: The entry keys sorted by their numeric suffix.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# The special self path holds the direct numeric entries of the module
|
|
50
|
+
if container_name == "$self":
|
|
51
|
+
return sorted(
|
|
52
|
+
[
|
|
53
|
+
sub_block_name for sub_block_name in sub_block_names
|
|
54
|
+
if sub_block_name.isdigit()
|
|
55
|
+
],
|
|
56
|
+
key=container_entry_sort_key
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Collect the sub-block keys of the container entries
|
|
60
|
+
keys: list[str] = [
|
|
61
|
+
sub_block_name for sub_block_name in sub_block_names
|
|
62
|
+
if sub_block_name.startswith(f"{container_name}.")
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
# Sort the entry keys by their numeric suffix
|
|
66
|
+
keys.sort(key=container_entry_sort_key)
|
|
67
|
+
|
|
68
|
+
# Return the ordered entry keys of the container
|
|
69
|
+
return keys
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Instruction types of the NNSchemaParser schema.
|
|
3
|
+
|
|
4
|
+
Each instruction represents one step of a block body and keeps the original
|
|
5
|
+
variable names of the parsed forward source.
|
|
6
|
+
|
|
7
|
+
Each instruction represents one step of a model block body, and keeps the
|
|
8
|
+
original variable names of the parsed Python code so the WebUI can display a
|
|
9
|
+
graph that maps back to the source.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
# Import Modules
|
|
13
|
+
from typing import Any, Callable
|
|
14
|
+
|
|
15
|
+
from torch import Tensor
|
|
16
|
+
|
|
17
|
+
from nnschemaparser.core.tensor_schema import TensorRepr, TensorReprWithValue
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class VarRef:
|
|
21
|
+
"""
|
|
22
|
+
Reference to a variable of the current block scope.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, name: str) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Init function.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
name (str): The name of the referenced variable.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# Store here the name of the referenced variable
|
|
34
|
+
self.name: str = name
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class BlockRef:
|
|
38
|
+
"""
|
|
39
|
+
Reference to a sub-block of the current block.
|
|
40
|
+
|
|
41
|
+
The path is the attribute name of the sub-block inside its parent module
|
|
42
|
+
(e.g. "attention"). For containers (nn.ModuleList, nn.ModuleDict), the
|
|
43
|
+
index_var is the name of the scope variable holding the index or the key.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, path: str, index_var: str | None = None) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Init function.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
path (str): The attribute path of the referenced sub-block.
|
|
52
|
+
index_var (str | None): The name of the scope variable holding the
|
|
53
|
+
container index, if the sub-block belongs to a container.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
# Store here the attribute path of the referenced sub-block
|
|
57
|
+
self.path: str = path
|
|
58
|
+
|
|
59
|
+
# Store here the index variable name for container sub-blocks
|
|
60
|
+
self.index_var: str | None = index_var
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Instruction:
|
|
64
|
+
"""
|
|
65
|
+
Base class of all the instructions of a block body.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(self, out_var: str) -> None:
|
|
69
|
+
"""
|
|
70
|
+
Init function.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
out_var (str): The name of the variable the result is bound to.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
# Store here the output variable name of the instruction
|
|
77
|
+
self.out_var: str = out_var
|
|
78
|
+
|
|
79
|
+
# This field is filled later by the shape resolution pass
|
|
80
|
+
self.resolved: TensorRepr | TensorReprWithValue | None = None
|
|
81
|
+
|
|
82
|
+
def resolve(self, value: Any, capture_values: bool = False) -> None:
|
|
83
|
+
"""
|
|
84
|
+
Fill the resolved representation of the instruction output.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
value (Any): The value produced by the instruction at execution.
|
|
88
|
+
capture_values (bool): If True, the tensor values are kept inside
|
|
89
|
+
the resolved representation.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
# If the value is a tensor, we store a tensor representation
|
|
93
|
+
if isinstance(value, Tensor):
|
|
94
|
+
|
|
95
|
+
# If values must be captured, keep a representation with the value
|
|
96
|
+
if capture_values:
|
|
97
|
+
self.resolved = TensorReprWithValue(
|
|
98
|
+
shape=tuple(int(dim) for dim in value.shape),
|
|
99
|
+
dtype=str(value.dtype),
|
|
100
|
+
value=value.detach()
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Else we only keep the shape and the dtype of the tensor
|
|
104
|
+
else:
|
|
105
|
+
self.resolved = TensorRepr(
|
|
106
|
+
shape=tuple(int(dim) for dim in value.shape),
|
|
107
|
+
dtype=str(value.dtype)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Else the value is a python literal, no shape is available
|
|
111
|
+
else:
|
|
112
|
+
self.resolved = TensorRepr(shape=(), dtype=type(value).__name__)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class OpInstruction(Instruction):
|
|
116
|
+
"""
|
|
117
|
+
Call to a torch operation or function (e.g. torch.nn.functional.softmax).
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __init__(
|
|
121
|
+
self,
|
|
122
|
+
target: Callable[..., Any] | VarRef,
|
|
123
|
+
qualified_name: str,
|
|
124
|
+
args: list[VarRef | Any],
|
|
125
|
+
kwargs: dict[str, VarRef | Any],
|
|
126
|
+
out_var: str,
|
|
127
|
+
kwargs_var: str | None = None,
|
|
128
|
+
args_var: str | None = None
|
|
129
|
+
) -> None:
|
|
130
|
+
"""
|
|
131
|
+
Init function.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
target (Callable[..., Any] | VarRef): The callable applied by the
|
|
135
|
+
instruction, or a variable reference to a callable resolved at
|
|
136
|
+
execution time (e.g. a method obtained with getattr).
|
|
137
|
+
qualified_name (str): The display name of the target
|
|
138
|
+
(e.g. "torch.nn.functional.softmax").
|
|
139
|
+
args (list[VarRef | Any]): The positional arguments, variable
|
|
140
|
+
references or literals.
|
|
141
|
+
kwargs (dict[str, VarRef | Any]): The keyword arguments, variable
|
|
142
|
+
references or literals.
|
|
143
|
+
out_var (str): The name of the variable the result is bound to.
|
|
144
|
+
kwargs_var (str | None): The name of a scope variable holding a dict
|
|
145
|
+
unpacked as extra keyword arguments (the **kwargs of the call).
|
|
146
|
+
args_var (str | None): The name of a scope variable holding a tuple
|
|
147
|
+
unpacked as extra positional arguments (the *args of the call).
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
# Init parent
|
|
151
|
+
super().__init__(out_var=out_var)
|
|
152
|
+
|
|
153
|
+
# Store here the callable applied by the instruction
|
|
154
|
+
self.target: Callable[..., Any] | VarRef = target
|
|
155
|
+
|
|
156
|
+
# Store here the display name of the target
|
|
157
|
+
self.qualified_name: str = qualified_name
|
|
158
|
+
|
|
159
|
+
# Store here the positional arguments of the call
|
|
160
|
+
self.args: list[VarRef | Any] = args
|
|
161
|
+
|
|
162
|
+
# Store here the keyword arguments of the call
|
|
163
|
+
self.kwargs: dict[str, VarRef | Any] = kwargs
|
|
164
|
+
|
|
165
|
+
# Store here the name of the unpacked keyword arguments variable
|
|
166
|
+
self.kwargs_var: str | None = kwargs_var
|
|
167
|
+
|
|
168
|
+
# Store here the name of the unpacked positional arguments variable
|
|
169
|
+
self.args_var: str | None = args_var
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class BlockInstruction(Instruction):
|
|
173
|
+
"""
|
|
174
|
+
Call to a sub-block of the current block.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def __init__(
|
|
178
|
+
self,
|
|
179
|
+
block_ref: BlockRef,
|
|
180
|
+
args: list[VarRef | Any],
|
|
181
|
+
out_var: str,
|
|
182
|
+
kwargs: dict[str, VarRef | Any] | None = None,
|
|
183
|
+
splat_args: bool = False,
|
|
184
|
+
kwargs_var: str | None = None,
|
|
185
|
+
args_var: str | None = None
|
|
186
|
+
) -> None:
|
|
187
|
+
"""
|
|
188
|
+
Init function.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
block_ref (BlockRef): The reference to the called sub-block.
|
|
192
|
+
args (list[VarRef | Any]): The positional arguments of the call.
|
|
193
|
+
When splat_args is True, this list holds a single variable
|
|
194
|
+
reference whose tuple value is unpacked as the arguments.
|
|
195
|
+
out_var (str): The name of the variable the result is bound to.
|
|
196
|
+
kwargs (dict[str, VarRef | Any] | None): The keyword arguments of
|
|
197
|
+
the call, bound to the sub-block inputs by name.
|
|
198
|
+
splat_args (bool): Whether the argument variable holds a tuple to
|
|
199
|
+
unpack as the positional arguments of the call.
|
|
200
|
+
kwargs_var (str | None): The name of a scope variable holding a dict
|
|
201
|
+
unpacked as extra keyword arguments (the **kwargs of the call).
|
|
202
|
+
args_var (str | None): The name of a scope variable holding a
|
|
203
|
+
tuple unpacked as extra positional arguments (the *args of
|
|
204
|
+
the call).
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
# Init parent
|
|
208
|
+
super().__init__(out_var=out_var)
|
|
209
|
+
|
|
210
|
+
# Store here the reference to the called sub-block
|
|
211
|
+
self.block_ref: BlockRef = block_ref
|
|
212
|
+
|
|
213
|
+
# Store here the arguments of the sub-block call
|
|
214
|
+
self.args: list[VarRef | Any] = args
|
|
215
|
+
|
|
216
|
+
# Store here the keyword arguments of the sub-block call
|
|
217
|
+
self.kwargs: dict[str, VarRef | Any] = kwargs or {}
|
|
218
|
+
|
|
219
|
+
# Store here whether the argument variable is unpacked as the arguments
|
|
220
|
+
self.splat_args: bool = splat_args
|
|
221
|
+
|
|
222
|
+
# Store here the name of the unpacked keyword arguments variable
|
|
223
|
+
self.kwargs_var: str | None = kwargs_var
|
|
224
|
+
|
|
225
|
+
# Store here the name of the unpacked positional arguments variable
|
|
226
|
+
self.args_var: str | None = args_var
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class ControlInstruction(Instruction):
|
|
230
|
+
"""
|
|
231
|
+
Control flow instruction, an if statement or a for loop.
|
|
232
|
+
|
|
233
|
+
For an if statement, the condition is an OpInstruction binding a temporary
|
|
234
|
+
variable of the block scope. For a for loop, the iterable is either an
|
|
235
|
+
OpInstruction, or the sub-block container referenced by iter_container,
|
|
236
|
+
whose entries are bound to bind_var (as sub-block schemas).
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
def __init__(
|
|
240
|
+
self,
|
|
241
|
+
kind: str,
|
|
242
|
+
condition: OpInstruction | None,
|
|
243
|
+
body: list[Instruction],
|
|
244
|
+
else_body: list[Instruction],
|
|
245
|
+
bind_var: str | None,
|
|
246
|
+
iter_container: BlockRef | None = None,
|
|
247
|
+
index_var: str | None = None,
|
|
248
|
+
out_var: str = ""
|
|
249
|
+
) -> None:
|
|
250
|
+
"""
|
|
251
|
+
Init function.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
kind (str): The kind of control flow, either "if" or "for".
|
|
255
|
+
condition (OpInstruction | None): The condition expression for an
|
|
256
|
+
if statement, the iterable expression for a for loop, or None
|
|
257
|
+
when iterating a container of sub-blocks.
|
|
258
|
+
body (list[Instruction]): The instructions of the main body.
|
|
259
|
+
else_body (list[Instruction]): The instructions of the else body.
|
|
260
|
+
bind_var (str | None): The name of the loop variable bound at each
|
|
261
|
+
iteration of a for loop.
|
|
262
|
+
iter_container (BlockRef | None): For a for loop over a container
|
|
263
|
+
of sub-blocks, the reference to the iterated container.
|
|
264
|
+
index_var (str | None): For a for loop with enumerate over a
|
|
265
|
+
container, the name of the variable bound to the index.
|
|
266
|
+
out_var (str): The name of the variable the result is bound to.
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
# Init parent
|
|
270
|
+
super().__init__(out_var=out_var)
|
|
271
|
+
|
|
272
|
+
# Only the if, for and while kinds are supported
|
|
273
|
+
if kind not in ("if", "for", "while"):
|
|
274
|
+
raise ValueError(f"Unsupported control flow kind: {kind}")
|
|
275
|
+
|
|
276
|
+
# Store here the kind of control flow
|
|
277
|
+
self.kind: str = kind
|
|
278
|
+
|
|
279
|
+
# Store here the condition or iterable expression of the control flow
|
|
280
|
+
self.condition: OpInstruction | None = condition
|
|
281
|
+
|
|
282
|
+
# Store here the instructions of the main body
|
|
283
|
+
self.body: list[Instruction] = body
|
|
284
|
+
|
|
285
|
+
# Store here the instructions of the else body
|
|
286
|
+
self.else_body: list[Instruction] = else_body
|
|
287
|
+
|
|
288
|
+
# Store here the name of the loop variable of a for loop
|
|
289
|
+
self.bind_var: str | None = bind_var
|
|
290
|
+
|
|
291
|
+
# Store here the iterated container reference of a for loop
|
|
292
|
+
self.iter_container: BlockRef | None = iter_container
|
|
293
|
+
|
|
294
|
+
# Store here the enumerate index variable of a for loop
|
|
295
|
+
self.index_var: str | None = index_var
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class TryInstruction(Instruction):
|
|
299
|
+
"""
|
|
300
|
+
Try instruction of a block body, with exception handlers and a finally.
|
|
301
|
+
|
|
302
|
+
The exception types of the handlers are resolved at lowering time and
|
|
303
|
+
stored as python classes. The name of the caught exception object is not
|
|
304
|
+
bound for now.
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
def __init__(
|
|
308
|
+
self,
|
|
309
|
+
body: list[Instruction],
|
|
310
|
+
handlers: list[tuple[tuple[type[BaseException], ...], list[Instruction]]],
|
|
311
|
+
handler_names: list[str | None],
|
|
312
|
+
final_body: list[Instruction],
|
|
313
|
+
out_var: str = ""
|
|
314
|
+
) -> None:
|
|
315
|
+
"""
|
|
316
|
+
Init function.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
body (list[Instruction]): The instructions of the try body.
|
|
320
|
+
handlers (list[tuple[tuple[type[BaseException], ...], list[Instruction]]]):
|
|
321
|
+
The exception types and bodies of the handlers.
|
|
322
|
+
handler_names (list[str | None]): The caught exception names of
|
|
323
|
+
the handlers, bound in the scope during their execution.
|
|
324
|
+
final_body (list[Instruction]): The instructions of the finally body.
|
|
325
|
+
out_var (str): The name of the variable the result is bound to.
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
# Init parent, a try instruction binds no new variable
|
|
329
|
+
super().__init__(out_var=out_var)
|
|
330
|
+
|
|
331
|
+
# Store here the instructions of the try body
|
|
332
|
+
self.body: list[Instruction] = body
|
|
333
|
+
|
|
334
|
+
# Store here the exception types and bodies of the handlers
|
|
335
|
+
self.handlers: list[
|
|
336
|
+
tuple[tuple[type[BaseException], ...], list[Instruction]]
|
|
337
|
+
] = handlers
|
|
338
|
+
|
|
339
|
+
# Store here the caught exception names of the handlers
|
|
340
|
+
self.handler_names: list[str | None] = handler_names
|
|
341
|
+
|
|
342
|
+
# Store here the instructions of the finally body
|
|
343
|
+
self.final_body: list[Instruction] = final_body
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class ReturnInstruction(Instruction):
|
|
347
|
+
"""
|
|
348
|
+
Return instruction of a block body.
|
|
349
|
+
|
|
350
|
+
A return instruction may be nested inside a control flow body, the
|
|
351
|
+
interpreter propagates its outputs up to the enclosing block.
|
|
352
|
+
"""
|
|
353
|
+
|
|
354
|
+
def __init__(self, out_vars: list[str]) -> None:
|
|
355
|
+
"""
|
|
356
|
+
Init function.
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
out_vars (list[str]): The names of the returned variables.
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
# Init parent, a return instruction binds no new variable
|
|
363
|
+
super().__init__(out_var="")
|
|
364
|
+
|
|
365
|
+
# Store here the names of the returned variables
|
|
366
|
+
self.out_vars: list[str] = out_vars
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class ContinueInstruction(Instruction):
|
|
370
|
+
"""
|
|
371
|
+
Continue instruction of a loop body.
|
|
372
|
+
|
|
373
|
+
The execution of the current iteration stops and the loop goes to its
|
|
374
|
+
next iteration, like the python continue statement.
|
|
375
|
+
"""
|
|
376
|
+
|
|
377
|
+
def __init__(self) -> None:
|
|
378
|
+
"""
|
|
379
|
+
Init function.
|
|
380
|
+
"""
|
|
381
|
+
|
|
382
|
+
# Init parent, a continue instruction binds no new variable
|
|
383
|
+
super().__init__(out_var="")
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class BreakInstruction(Instruction):
|
|
387
|
+
"""
|
|
388
|
+
Break instruction of a loop body.
|
|
389
|
+
|
|
390
|
+
The execution of the loop stops, like the python break statement.
|
|
391
|
+
"""
|
|
392
|
+
|
|
393
|
+
def __init__(self) -> None:
|
|
394
|
+
"""
|
|
395
|
+
Init function.
|
|
396
|
+
"""
|
|
397
|
+
|
|
398
|
+
# Init parent, a break instruction binds no new variable
|
|
399
|
+
super().__init__(out_var="")
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core schema types of NNSchemaParser.
|
|
3
|
+
|
|
4
|
+
A parsed model is a tree of ModelBlockSchema blocks, each holding its inputs,
|
|
5
|
+
outputs, weights, sub-blocks and the instruction list of its forward body.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Import Modules
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from nnschemaparser.core.instructions import Instruction
|
|
12
|
+
from nnschemaparser.core.tensor_schema import TensorRepr, TensorReprWithValue
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ModelBlockSchema:
|
|
16
|
+
"""
|
|
17
|
+
Schema of one block of a parsed model.
|
|
18
|
+
|
|
19
|
+
A block mirrors one nn.Module of the source model: its forward parameters,
|
|
20
|
+
its returned values, its direct parameters and buffers, its child modules
|
|
21
|
+
as sub-blocks, and the lowered body of its forward method.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
inputs: dict[str, TensorRepr],
|
|
27
|
+
outputs: list[TensorRepr],
|
|
28
|
+
weights: dict[str, TensorReprWithValue],
|
|
29
|
+
sub_blocks: dict[str, "ModelBlockSchema"],
|
|
30
|
+
body: list[Instruction],
|
|
31
|
+
module: Any | None = None,
|
|
32
|
+
methods: dict[str, "ModelBlockSchema"] | None = None,
|
|
33
|
+
method_name: str | None = None,
|
|
34
|
+
input_defaults: dict[str, Any] | None = None,
|
|
35
|
+
skipped: dict[str, str] | None = None
|
|
36
|
+
) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Init function.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
inputs (dict[str, TensorRepr]): The list of all named input values of the model
|
|
42
|
+
(often one X value)
|
|
43
|
+
outputs (list[TensorRepr]): The list of all named output values of the model
|
|
44
|
+
(often one Y value)
|
|
45
|
+
weights: dict[str, TensorReprWithValue]: The weights of the current block.
|
|
46
|
+
sub_blocks (dict[str, ModelBlockSchema]): The list of all the sub block of the model
|
|
47
|
+
(all the other nn.Modules in the model class attribute)
|
|
48
|
+
body (list[Instruction]): What is happening inside the current model block
|
|
49
|
+
(the graph that will be shown in the webUI)
|
|
50
|
+
module (Any | None): The source module of the block, used by the
|
|
51
|
+
interpreter to resolve dynamic attributes.
|
|
52
|
+
methods (dict[str, ModelBlockSchema] | None): The other methods of the
|
|
53
|
+
source module called by the body, parsed
|
|
54
|
+
as block schemas (e.g. get_image_features).
|
|
55
|
+
method_name (str | None): The name of the parsed method when the block
|
|
56
|
+
describes a method instead of the forward.
|
|
57
|
+
input_defaults (dict[str, Any] | None): The default values of the
|
|
58
|
+
optional inputs, by parameter name.
|
|
59
|
+
skipped (dict[str, str] | None): The children of the module that
|
|
60
|
+
could not be parsed, by name with
|
|
61
|
+
their skip reasons. They are
|
|
62
|
+
reached at run time through the
|
|
63
|
+
source module instead.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
# Store here the model input(s) representation(s)
|
|
67
|
+
self.inputs: dict[str, TensorRepr] = inputs
|
|
68
|
+
|
|
69
|
+
# Store here the model output(s) representation(s)
|
|
70
|
+
self.outputs: list[TensorRepr] = outputs
|
|
71
|
+
|
|
72
|
+
# Store here the weights of the block
|
|
73
|
+
self.weights: dict[str, TensorReprWithValue] = weights
|
|
74
|
+
|
|
75
|
+
# Store here the model sub blocks
|
|
76
|
+
self.sub_blocks: dict[str, ModelBlockSchema] = sub_blocks
|
|
77
|
+
|
|
78
|
+
# Store here the model body list of instructions / expressions
|
|
79
|
+
self.body: list[Instruction] = body
|
|
80
|
+
|
|
81
|
+
# Store here the source module of the block
|
|
82
|
+
self.module: Any | None = module
|
|
83
|
+
|
|
84
|
+
# Store here the other methods of the module called by the body
|
|
85
|
+
self.methods: dict[str, ModelBlockSchema] = methods or {}
|
|
86
|
+
|
|
87
|
+
# Store here the default values of the optional inputs
|
|
88
|
+
self.input_defaults: dict[str, Any] = input_defaults or {}
|
|
89
|
+
|
|
90
|
+
# Store here the skipped children re-dispatched at run time
|
|
91
|
+
self.skipped: dict[str, str] = skipped or {}
|
|
92
|
+
|
|
93
|
+
# Store here the name of the described method, if not the forward
|
|
94
|
+
self.method_name: str | None = method_name
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tensor representation types of NNSchemaParser.
|
|
3
|
+
|
|
4
|
+
A TensorRepr describes a tensor flowing through the graph by its shape and its
|
|
5
|
+
dtype, and TensorReprWithValue additionally holds the value itself.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Import Modules
|
|
9
|
+
from torch import Tensor
|
|
10
|
+
|
|
11
|
+
# The placeholder dtype of unresolved tensor representations
|
|
12
|
+
PLACEHOLDER_DTYPE: str = ""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TensorRepr:
|
|
16
|
+
"""
|
|
17
|
+
Representation of a tensor flowing through the graph, without its value.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, shape: tuple[int, ...], dtype: str) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Init function.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
shape (tuple[int | str, ...]): shape of the tensor, the str type is for symbolic values
|
|
26
|
+
dtype (str): The type of the tensor's values
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Store here the shape of the tensor
|
|
30
|
+
self.shape: tuple[int, ...] = shape
|
|
31
|
+
|
|
32
|
+
# Store here the type of the tensor
|
|
33
|
+
self.dtype: str = dtype
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TensorReprWithValue(TensorRepr):
|
|
37
|
+
"""
|
|
38
|
+
Representation of a tensor keeping a snapshot of its value.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(self, shape: tuple[int, ...], dtype: str, value: Tensor) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Init function.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
shape (tuple[int, ...]): Shape of the tensor.
|
|
47
|
+
dtype (str): The type of the tensor's values.
|
|
48
|
+
value (Tensor): The value of the tensor.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# Init parent
|
|
52
|
+
super().__init__(shape=shape, dtype=dtype)
|
|
53
|
+
|
|
54
|
+
# Store here the value of the tensor
|
|
55
|
+
self.value: Tensor = value
|