onnxscript 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.
Files changed (176) hide show
  1. onnxscript/__init__.py +131 -0
  2. onnxscript/_framework_apis/__init__.py +3 -0
  3. onnxscript/_framework_apis/torch_2_5.py +117 -0
  4. onnxscript/_framework_apis/torch_2_6.py +45 -0
  5. onnxscript/_internal/__init__.py +0 -0
  6. onnxscript/_internal/analysis.py +229 -0
  7. onnxscript/_internal/ast_utils.py +64 -0
  8. onnxscript/_internal/autocast.py +250 -0
  9. onnxscript/_internal/deprecation.py +78 -0
  10. onnxscript/_internal/param_manipulation.py +148 -0
  11. onnxscript/_internal/runtime_typing.py +43 -0
  12. onnxscript/_internal/utils.py +99 -0
  13. onnxscript/_internal/version_utils.py +118 -0
  14. onnxscript/_legacy_ir/__init__.py +341 -0
  15. onnxscript/_legacy_ir/visitor.py +937 -0
  16. onnxscript/_thirdparty/asciichartpy.py +313 -0
  17. onnxscript/backend/__init__.py +2 -0
  18. onnxscript/backend/onnx_backend.py +303 -0
  19. onnxscript/backend/onnx_export.py +885 -0
  20. onnxscript/converter.py +1470 -0
  21. onnxscript/evaluator.py +619 -0
  22. onnxscript/function_libs/tools/torch_lib/deduce_type_constraints.py +403 -0
  23. onnxscript/function_libs/tools/torch_lib/generate_aten_signatures.py +333 -0
  24. onnxscript/function_libs/tools/torch_lib/generate_prims_signatures.py +331 -0
  25. onnxscript/function_libs/torch_lib/__init__.py +12 -0
  26. onnxscript/function_libs/torch_lib/_constants.py +5 -0
  27. onnxscript/function_libs/torch_lib/_flags.py +58 -0
  28. onnxscript/function_libs/torch_lib/graph_building/__init__.py +56 -0
  29. onnxscript/function_libs/torch_lib/graph_building/_graph_building_ir.py +723 -0
  30. onnxscript/function_libs/torch_lib/graph_building/_graph_building_torch.py +1125 -0
  31. onnxscript/function_libs/torch_lib/ops/__init__.py +27 -0
  32. onnxscript/function_libs/torch_lib/ops/common.py +80 -0
  33. onnxscript/function_libs/torch_lib/ops/core.py +8935 -0
  34. onnxscript/function_libs/torch_lib/ops/fft.py +385 -0
  35. onnxscript/function_libs/torch_lib/ops/linalg.py +399 -0
  36. onnxscript/function_libs/torch_lib/ops/nested.py +25 -0
  37. onnxscript/function_libs/torch_lib/ops/nn.py +2713 -0
  38. onnxscript/function_libs/torch_lib/ops/prims.py +850 -0
  39. onnxscript/function_libs/torch_lib/ops/quantized_decomposed.py +63 -0
  40. onnxscript/function_libs/torch_lib/ops/sparse.py +23 -0
  41. onnxscript/function_libs/torch_lib/ops/special.py +387 -0
  42. onnxscript/function_libs/torch_lib/ops/vision.py +25 -0
  43. onnxscript/function_libs/torch_lib/registration.py +151 -0
  44. onnxscript/function_libs/torch_lib/tensor_typing.py +74 -0
  45. onnxscript/ir/__init__.py +153 -0
  46. onnxscript/ir/_convenience.py +447 -0
  47. onnxscript/ir/_core.py +3119 -0
  48. onnxscript/ir/_display.py +49 -0
  49. onnxscript/ir/_enums.py +163 -0
  50. onnxscript/ir/_graph_comparison.py +23 -0
  51. onnxscript/ir/_io.py +97 -0
  52. onnxscript/ir/_linked_list.py +276 -0
  53. onnxscript/ir/_metadata.py +44 -0
  54. onnxscript/ir/_name_authority.py +72 -0
  55. onnxscript/ir/_polyfill.py +25 -0
  56. onnxscript/ir/_protocols.py +598 -0
  57. onnxscript/ir/_schemas.py +548 -0
  58. onnxscript/ir/_tape.py +120 -0
  59. onnxscript/ir/_type_casting.py +106 -0
  60. onnxscript/ir/convenience.py +32 -0
  61. onnxscript/ir/external_data.py +396 -0
  62. onnxscript/ir/passes/__init__.py +33 -0
  63. onnxscript/ir/passes/_pass_infra.py +172 -0
  64. onnxscript/ir/serde.py +1620 -0
  65. onnxscript/ir/tensor_adapters.py +122 -0
  66. onnxscript/ir/traversal.py +82 -0
  67. onnxscript/irbuilder.py +542 -0
  68. onnxscript/main.py +167 -0
  69. onnxscript/onnx_opset/__init__.py +232 -0
  70. onnxscript/onnx_opset/_impl/opset1.py +4100 -0
  71. onnxscript/onnx_opset/_impl/opset10.py +1227 -0
  72. onnxscript/onnx_opset/_impl/opset11.py +4013 -0
  73. onnxscript/onnx_opset/_impl/opset12.py +1078 -0
  74. onnxscript/onnx_opset/_impl/opset13.py +3924 -0
  75. onnxscript/onnx_opset/_impl/opset14.py +999 -0
  76. onnxscript/onnx_opset/_impl/opset15.py +604 -0
  77. onnxscript/onnx_opset/_impl/opset16.py +1255 -0
  78. onnxscript/onnx_opset/_impl/opset17.py +561 -0
  79. onnxscript/onnx_opset/_impl/opset18.py +1803 -0
  80. onnxscript/onnx_opset/_impl/opset19.py +1942 -0
  81. onnxscript/onnx_opset/_impl/opset2.py +218 -0
  82. onnxscript/onnx_opset/_impl/opset20.py +675 -0
  83. onnxscript/onnx_opset/_impl/opset21.py +1976 -0
  84. onnxscript/onnx_opset/_impl/opset22.py +2588 -0
  85. onnxscript/onnx_opset/_impl/opset3.py +199 -0
  86. onnxscript/onnx_opset/_impl/opset4.py +77 -0
  87. onnxscript/onnx_opset/_impl/opset5.py +84 -0
  88. onnxscript/onnx_opset/_impl/opset6.py +944 -0
  89. onnxscript/onnx_opset/_impl/opset7.py +1243 -0
  90. onnxscript/onnx_opset/_impl/opset8.py +444 -0
  91. onnxscript/onnx_opset/_impl/opset9.py +1485 -0
  92. onnxscript/onnx_opset/_impl/opset_ai_onnx_ml1.py +974 -0
  93. onnxscript/onnx_opset/_impl/opset_ai_onnx_ml2.py +112 -0
  94. onnxscript/onnx_opset/_impl/opset_ai_onnx_ml3.py +308 -0
  95. onnxscript/onnx_opset/_impl/opset_ai_onnx_ml4.py +129 -0
  96. onnxscript/onnx_opset/_impl/opset_ai_onnx_ml5.py +158 -0
  97. onnxscript/onnx_opset/_impl/opset_ai_onnx_preview_training1.py +577 -0
  98. onnxscript/onnx_types.py +229 -0
  99. onnxscript/optimizer/__init__.py +39 -0
  100. onnxscript/optimizer/_constant_folding.py +1083 -0
  101. onnxscript/optimizer/_inliner.py +312 -0
  102. onnxscript/optimizer/_legacy/_optimizer.py +98 -0
  103. onnxscript/optimizer/_legacy/_remove_unused_proto.py +144 -0
  104. onnxscript/optimizer/_legacy/_simple_function_folding.py +243 -0
  105. onnxscript/optimizer/_legacy/constant_folding.py +293 -0
  106. onnxscript/optimizer/_legacy/evaluator.py +439 -0
  107. onnxscript/optimizer/_optimizer.py +61 -0
  108. onnxscript/optimizer/_remove_unused.py +106 -0
  109. onnxscript/optimizer/_remove_unused_function.py +72 -0
  110. onnxscript/py.typed +1 -0
  111. onnxscript/rewriter/__init__.py +56 -0
  112. onnxscript/rewriter/_ir_utils.py +111 -0
  113. onnxscript/rewriter/broadcast_to_matmul.py +180 -0
  114. onnxscript/rewriter/cast_constant_of_shape.py +50 -0
  115. onnxscript/rewriter/collapse_slices.py +141 -0
  116. onnxscript/rewriter/erfgelu.py +27 -0
  117. onnxscript/rewriter/function_rule.py +232 -0
  118. onnxscript/rewriter/gemm_to_matmul_add.py +21 -0
  119. onnxscript/rewriter/generic_pattern.py +700 -0
  120. onnxscript/rewriter/llama_rule_sets.py +287 -0
  121. onnxscript/rewriter/no_op.py +56 -0
  122. onnxscript/rewriter/onnxruntime/__init__.py +50 -0
  123. onnxscript/rewriter/onnxruntime/bfloat16_utils/bfloat16_converter.py +99 -0
  124. onnxscript/rewriter/onnxruntime/fused_matmul_rule_sets.py +177 -0
  125. onnxscript/rewriter/onnxruntime/group_normalization_merge_silu.py +64 -0
  126. onnxscript/rewriter/onnxruntime/instance_to_group_normalization.py +155 -0
  127. onnxscript/rewriter/onnxruntime/softmax.py +63 -0
  128. onnxscript/rewriter/onnxruntime/transformers/__init__.py +21 -0
  129. onnxscript/rewriter/onnxruntime/transformers/biassplitgelu.py +31 -0
  130. onnxscript/rewriter/onnxruntime/transformers/fastgelu.py +29 -0
  131. onnxscript/rewriter/onnxruntime/transformers/layernorm.py +47 -0
  132. onnxscript/rewriter/onnxruntime/transformers/multihead_attention.py +715 -0
  133. onnxscript/rewriter/ort_fusions/__init__.py +9 -0
  134. onnxscript/rewriter/ort_fusions/_core.py +28 -0
  135. onnxscript/rewriter/ort_fusions/_smollm_1.py +253 -0
  136. onnxscript/rewriter/ort_fusions/_smollm_2.py +467 -0
  137. onnxscript/rewriter/ort_fusions/_test_models.py +122 -0
  138. onnxscript/rewriter/ort_fusions/_test_utils.py +42 -0
  139. onnxscript/rewriter/ort_fusions/cos_sin_cache.py +154 -0
  140. onnxscript/rewriter/ort_fusions/gqa.py +156 -0
  141. onnxscript/rewriter/ort_fusions/mha.py +198 -0
  142. onnxscript/rewriter/ort_fusions/rms_normalization.py +95 -0
  143. onnxscript/rewriter/ort_fusions/rotary_embedding.py +64 -0
  144. onnxscript/rewriter/ort_fusions/sdpa.py +75 -0
  145. onnxscript/rewriter/ort_fusions/skip_normalization.py +46 -0
  146. onnxscript/rewriter/pattern.py +1714 -0
  147. onnxscript/rewriter/testing.py +77 -0
  148. onnxscript/sourceinfo.py +59 -0
  149. onnxscript/tensor.py +227 -0
  150. onnxscript/testing/__init__.py +482 -0
  151. onnxscript/tools/__init__.py +4 -0
  152. onnxscript/tools/benchmark/__init__.py +23 -0
  153. onnxscript/tools/benchmark/benchmark_helpers.py +783 -0
  154. onnxscript/tools/benchmark/benchmark_run.py +140 -0
  155. onnxscript/tools/benchmark/export_model.py +207 -0
  156. onnxscript/tools/benchmark/export_model_batch.py +146 -0
  157. onnxscript/tools/memory_peak.py +244 -0
  158. onnxscript/tools/training_helper.py +50 -0
  159. onnxscript/tools/transformers_models/__init__.py +190 -0
  160. onnxscript/tools/transformers_models/llama.py +168 -0
  161. onnxscript/tools/transformers_models/mistral.py +238 -0
  162. onnxscript/tools/transformers_models/phi.py +248 -0
  163. onnxscript/tools/transformers_models/phi3.py +259 -0
  164. onnxscript/type_annotation.py +281 -0
  165. onnxscript/utils/__init__.py +0 -0
  166. onnxscript/utils/evaluation_utils.py +56 -0
  167. onnxscript/utils/timing_utils.py +33 -0
  168. onnxscript/utils/utils.py +84 -0
  169. onnxscript/values.py +790 -0
  170. onnxscript/version_converter/__init__.py +21 -0
  171. onnxscript/version_converter/_version_converter.py +314 -0
  172. onnxscript-0.1.0.dist-info/LICENSE +21 -0
  173. onnxscript-0.1.0.dist-info/METADATA +370 -0
  174. onnxscript-0.1.0.dist-info/RECORD +176 -0
  175. onnxscript-0.1.0.dist-info/WHEEL +5 -0
  176. onnxscript-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,118 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """Version utils for testing."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import warnings
8
+ from typing import Callable, Sequence
9
+
10
+ import packaging.version
11
+
12
+
13
+ def onnx_older_than(version: str) -> bool:
14
+ """Returns True if the ONNX version is older than the given version."""
15
+ import onnx # pylint: disable=import-outside-toplevel
16
+
17
+ return (
18
+ packaging.version.parse(onnx.__version__).release
19
+ < packaging.version.parse(version).release
20
+ )
21
+
22
+
23
+ def torch_older_than(version: str) -> bool:
24
+ """Returns True if the torch version is older than the given version."""
25
+ import torch # pylint: disable=import-outside-toplevel
26
+
27
+ return (
28
+ packaging.version.parse(torch.__version__).release
29
+ < packaging.version.parse(version).release
30
+ )
31
+
32
+
33
+ def transformers_older_than(version: str) -> bool | None:
34
+ """Returns True if the transformers version is older than the given version."""
35
+ try:
36
+ import transformers # pylint: disable=import-outside-toplevel
37
+ except ImportError:
38
+ return None
39
+
40
+ return (
41
+ packaging.version.parse(transformers.__version__).release
42
+ < packaging.version.parse(version).release
43
+ )
44
+
45
+
46
+ def is_onnxruntime_training() -> bool:
47
+ """Returns True if the onnxruntime is onnxruntime-training."""
48
+ try:
49
+ from onnxruntime import training # pylint: disable=import-outside-toplevel
50
+
51
+ assert training
52
+ except ImportError:
53
+ # onnxruntime not training
54
+ return False
55
+
56
+ try:
57
+ from onnxruntime.capi.onnxruntime_pybind11_state import ( # pylint: disable=import-outside-toplevel
58
+ OrtValueVector,
59
+ )
60
+ except ImportError:
61
+ return False
62
+
63
+ return hasattr(OrtValueVector, "push_back_batch")
64
+
65
+
66
+ def onnxruntime_older_than(version: str) -> bool:
67
+ """Returns True if the onnxruntime version is older than the given version."""
68
+ import onnxruntime # pylint: disable=import-outside-toplevel
69
+
70
+ return (
71
+ packaging.version.parse(onnxruntime.__version__).release
72
+ < packaging.version.parse(version).release
73
+ )
74
+
75
+
76
+ def numpy_older_than(version: str) -> bool:
77
+ """Returns True if the numpy version is older than the given version."""
78
+ import numpy # pylint: disable=import-outside-toplevel
79
+
80
+ return (
81
+ packaging.version.parse(numpy.__version__).release
82
+ < packaging.version.parse(version).release
83
+ )
84
+
85
+
86
+ def has_transformers():
87
+ """Tells if transformers is installed."""
88
+ try:
89
+ import transformers # pylint: disable=import-outside-toplevel
90
+
91
+ assert transformers
92
+ return True # noqa
93
+ except ImportError:
94
+ return False
95
+
96
+
97
+ def ignore_warnings(warns: Warning | Sequence[Warning]) -> Callable: # type: ignore[arg-type]
98
+ """Catches warnings.
99
+
100
+ Args:
101
+ warns: warnings to ignore
102
+
103
+ Returns:
104
+ decorated function
105
+ """
106
+
107
+ def wrapper(fct):
108
+ if warns is None:
109
+ raise AssertionError(f"warns cannot be None for '{fct}'.")
110
+
111
+ def call_f(self):
112
+ with warnings.catch_warnings():
113
+ warnings.simplefilter("ignore", warns) # type: ignore[arg-type]
114
+ return fct(self)
115
+
116
+ return call_f
117
+
118
+ return wrapper
@@ -0,0 +1,341 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ from __future__ import annotations
4
+
5
+ import dataclasses
6
+ from collections import deque
7
+ from typing import List, Tuple, Union
8
+
9
+ import numpy as np
10
+ import onnx
11
+
12
+
13
+ class Unknown:
14
+ """A special value used to indicate that a value is not a statically known constant.
15
+
16
+ We use this instead of None because None is a valid constant value (since ONNX
17
+ supports the Optional type).
18
+ """
19
+
20
+ instance = None
21
+
22
+ def __init__(self) -> None:
23
+ if Unknown.instance is not None:
24
+ raise ValueError("Unknown.instance is already set")
25
+ Unknown.instance = self
26
+
27
+
28
+ # Singleton instance of Unknown
29
+ unknown = Unknown()
30
+ NotConstant = unknown
31
+
32
+ # ConcreteValue: This type represents constant values that an ONNX variable can take.
33
+ # TODO: Extend this to a recursive type to handle lists of tensors, etc., support optionals,
34
+ # maps, etc.
35
+ # TODO (rama): The value is sometimes stored as a numpy array, and sometimes as an ONNX TensorProto.
36
+ # A uniform representation would be helpful, but we should avoid unnecessary conversions for
37
+ # large tensors. Should be cleaned up in the new IR.
38
+ ConcreteValue = Union[onnx.TensorProto, np.ndarray, Unknown, None]
39
+
40
+ # SymbolicValue: This information is used to enable partial-evaluation and specialization
41
+ # of sequence operations, as well as elimination of redundant Identity ops.
42
+ # The symbolic value of a variable X can be:
43
+ # - a string with the value "Y", indicating that "X" is a copy of "Y"
44
+ # - a list of strings, indicating that "X" is a list of tensors, with their symbolic values
45
+ # Eg., the symbolic value ["A", "B", "C"] indicates that the value of X is equal to
46
+ # "SequenceConstruct(A, B, C)".
47
+ # TODO: Technically, SymbolicValue should be a recursive type to handle lists of lists of
48
+ # tensors, etc. However, we currently only handle lists of tensors.
49
+
50
+ SymbolicValue = Union[str, List[str]]
51
+
52
+ FunctionId = Tuple[str, str, str]
53
+
54
+
55
+ def get_function_id(function: onnx.FunctionProto) -> FunctionId:
56
+ return (function.domain, function.name, getattr(function, "overload", ""))
57
+
58
+
59
+ def get_function_id_from_node(node: onnx.NodeProto) -> FunctionId:
60
+ return (node.domain, node.op_type, getattr(node, "overload", ""))
61
+
62
+
63
+ @dataclasses.dataclass
64
+ class StaticValueInfo:
65
+ name: str
66
+ value: ConcreteValue = NotConstant
67
+ type: onnx.TypeProto | None = None
68
+ symbolic_value: SymbolicValue | None = None
69
+
70
+ def is_copy(self) -> bool:
71
+ return isinstance(self.symbolic_value, str)
72
+
73
+ def tensor_shape_proto(self) -> onnx.TensorShapeProto | None:
74
+ """Returns the shape of a tensor or None.
75
+
76
+ A return value of None could mean that the type is unknown or that the type is not a tensor
77
+ or that the tensor shape (that is, even the rank) is unknown.
78
+ """
79
+ type = self.type
80
+ if type and type.HasField("tensor_type") and type.tensor_type.HasField("shape"):
81
+ return type.tensor_type.shape
82
+ return None
83
+
84
+ @property
85
+ def shape(self) -> list[str | int | None] | None:
86
+ """Returns the shape in a list.
87
+
88
+ Str means that the shape is dynamic.
89
+ """
90
+ type = self.type
91
+ if type and type.HasField("tensor_type") and type.tensor_type.HasField("shape"):
92
+ dims = []
93
+ for dim in type.tensor_type.shape.dim:
94
+ if dim.HasField("dim_param"):
95
+ dims.append(dim.dim_param)
96
+ elif dim.HasField("dim_value"):
97
+ dims.append(dim.dim_value)
98
+ else:
99
+ dims.append(None)
100
+ return dims
101
+ if self.value_as_np_array is not None:
102
+ return list(self.value_as_np_array.shape)
103
+ return None
104
+
105
+ @property
106
+ def element_type(self) -> int | None:
107
+ """Returns the element type of a tensor, or None if type is not known or is not a tensor."""
108
+ type = self.type
109
+ if type and type.HasField("tensor_type"):
110
+ return type.tensor_type.elem_type
111
+ return None
112
+
113
+ def identity_merge_from(self, other: StaticValueInfo) -> None:
114
+ """Merge the value of other into self.
115
+
116
+ This models the effect of an identity (copy) operation.
117
+ This will update static-analysis information based on incoming value.
118
+ """
119
+ if not isinstance(other, StaticValueInfo):
120
+ raise TypeError(f"Cannot merge {other} into {self}.")
121
+ if other.value is not NotConstant:
122
+ self.value = other.value
123
+ # TODO: merge and combine best shape information from both types.
124
+ if other.tensor_shape_proto() is not None and other.element_type is not None:
125
+ self.type = other.type
126
+ # We cannot copy symbolic value across different scopes.
127
+
128
+ # WIP: Extensions towards new IR: Note that the default construction of StaticValueInfo
129
+ # does not fill in the following fields. These fields are filled in by the IRBuilder
130
+ # which constructs the IR from the ONNX model.
131
+ node: Node | None = None
132
+ uses: list[Node] = dataclasses.field(default_factory=list)
133
+ output_index: int | None = None
134
+ is_output: bool = False
135
+
136
+ @property
137
+ def const_value(self) -> ConcreteValue:
138
+ return self.value
139
+
140
+ @property
141
+ def value_as_np_array(self) -> np.ndarray | None:
142
+ if isinstance(self.value, np.ndarray):
143
+ return self.value
144
+ if isinstance(self.value, onnx.TensorProto):
145
+ return onnx.numpy_helper.to_array(self.value)
146
+ return None
147
+
148
+ def def_node(self) -> Node | None:
149
+ return self.node
150
+
151
+ def def_index(self) -> int:
152
+ return self.output_index # type: ignore[return-value]
153
+
154
+ def is_same_as(self, other: StaticValueInfo) -> bool:
155
+ """Returns true if this value represents the same IR object as the other value.
156
+
157
+ This is *not* value-equality, but rather object-equality.
158
+ """
159
+ return self is other
160
+
161
+ def __str__(self) -> str:
162
+ shape = self.shape
163
+ if shape is not None:
164
+ shape = [str(dim) for dim in shape]
165
+ shape_str = f"[{', '.join(shape)}]" # type: ignore[arg-type]
166
+ else:
167
+ shape_str = "None"
168
+ return (
169
+ f"StaticValueInfo({self.name}, shape:{shape_str}, dtype:{self.element_type}, "
170
+ f"{'has const value' if self.value is not unknown else 'no const value'}.)"
171
+ )
172
+
173
+
174
+ Value = StaticValueInfo
175
+
176
+
177
+ class Model:
178
+ def __init__(self) -> None:
179
+ self.gen_var_counter: int = 0
180
+
181
+ def set(
182
+ self,
183
+ model_proto: onnx.ModelProto,
184
+ graph: Graph,
185
+ functions: list[Function],
186
+ version_map: dict[str, int],
187
+ ) -> None:
188
+ """TODO. This is a temporary patch."""
189
+ self.original_model_proto = model_proto
190
+ self.graph = graph
191
+ self.functions = functions
192
+ self.version_map = version_map
193
+
194
+ def make_new_name(self):
195
+ # Temporary hack.
196
+ self.gen_var_counter += 1
197
+ return f"_gen_{self.gen_var_counter}"
198
+
199
+ def __str__(self) -> str:
200
+ # TODO: Naive string representation for debugging. Need to improve this.
201
+ return "\n".join(
202
+ [
203
+ f"ModelGraph: {self.graph}",
204
+ f"Functions: {self.functions}",
205
+ f"VersionMap: {self.version_map}",
206
+ ]
207
+ )
208
+
209
+
210
+ class Graph:
211
+ def __init__(self, graph_proto: onnx.GraphProto):
212
+ self.original_graph_proto = graph_proto
213
+ self.nodes: deque[Node] = deque()
214
+ self.values: dict[str, Value] = {}
215
+
216
+ @property
217
+ def name(self) -> str:
218
+ return self.original_graph_proto.name
219
+
220
+ def __str__(self) -> str:
221
+ return "\n".join(
222
+ [
223
+ "Graph",
224
+ f"Nodes: {[str(n) for n in self.nodes]}",
225
+ f"Values: {[str(v) for v in self.values]}",
226
+ ]
227
+ )
228
+
229
+ @property
230
+ def input_names(self) -> list[str]:
231
+ return [_.name for _ in self.original_graph_proto.input]
232
+
233
+ @property
234
+ def output_names(self) -> list[str]:
235
+ return [_.name for _ in self.original_graph_proto.output]
236
+
237
+
238
+ class Function:
239
+ def __init__(self, function_proto: onnx.FunctionProto):
240
+ self.original_function_proto = function_proto
241
+ self.nodes = deque() # type: ignore[var-annotated]
242
+ self.values = {} # type: ignore[var-annotated]
243
+
244
+ @property
245
+ def id(self) -> FunctionId:
246
+ return (self.domain, self.name, self.overload)
247
+
248
+ @property
249
+ def domain(self) -> str:
250
+ return self.original_function_proto.domain
251
+
252
+ @property
253
+ def name(self) -> str:
254
+ return self.original_function_proto.name
255
+
256
+ @property
257
+ def overload(self) -> str:
258
+ return getattr(self.original_function_proto, "overload", "")
259
+
260
+ def __str__(self) -> str:
261
+ return "\n".join(
262
+ [
263
+ "Function",
264
+ f"Nodes: {[str(n) for n in self.nodes]}",
265
+ f"Values: {[str(v) for v in self.values]}",
266
+ ]
267
+ )
268
+
269
+
270
+ class RefAttr:
271
+ def __init__(self, name: str, ref_attr_name: str, type) -> None:
272
+ self.name = name
273
+ self.ref_attr_name = ref_attr_name
274
+ self.type = type
275
+
276
+ def to_proto(self) -> onnx.AttributeProto:
277
+ attr_proto = onnx.AttributeProto()
278
+ attr_proto.name = self.name
279
+ attr_proto.ref_attr_name = self.ref_attr_name
280
+ attr_proto.type = self.type
281
+ return attr_proto
282
+
283
+
284
+ class Node:
285
+ def __init__(
286
+ self,
287
+ node_proto: onnx.NodeProto,
288
+ populate_io: bool = False,
289
+ ) -> None:
290
+ self.original_node_proto = node_proto
291
+ self.domain: str = node_proto.domain
292
+ self.version: int | None = None
293
+ self.op_type: str = node_proto.op_type
294
+ if populate_io:
295
+ self.inputs: list[Value | None] = [Value(i) for i in node_proto.input]
296
+ self.outputs: list[Value | None] = [Value(i) for i in node_proto.output]
297
+ else:
298
+ self.inputs: list[Value | None] = [] # type: ignore[no-redef]
299
+ self.outputs: list[Value | None] = [] # type: ignore[no-redef]
300
+ # TODO: attributes are never populated.
301
+ self.attributes: dict[str, int | float | RefAttr | Graph | list[Graph]] = {}
302
+
303
+ def __repr__(self) -> str:
304
+ return (
305
+ f"{self.op_type}({','.join(self.original_node_proto.input)})"
306
+ f"->{','.join(self.original_node_proto.output)}"
307
+ )
308
+
309
+ @property
310
+ def name(self) -> str:
311
+ return self.original_node_proto.name
312
+
313
+ @property
314
+ def input_names(self):
315
+ return self.original_node_proto.input
316
+
317
+ @property
318
+ def output_names(self):
319
+ return self.original_node_proto.output
320
+
321
+ @property
322
+ def attribute(self):
323
+ return self.original_node_proto.attribute
324
+
325
+ def set_version_if_custom_op(self, version_map: dict[str, int]) -> None:
326
+ if self.domain != "" and self.domain in version_map:
327
+ self.version = version_map[self.domain]
328
+
329
+ def get_attribute(self, name: str) -> int | float | None:
330
+ return self.attributes.get(name, None) # type: ignore[return-value]
331
+
332
+ def __str__(self) -> str:
333
+ return "\n".join(
334
+ [
335
+ "Node",
336
+ f"OpType: {self.op_type}",
337
+ f"Inputs: {self.inputs}",
338
+ f"Outputs: {self.outputs}",
339
+ f"Attributes: {self.attributes}",
340
+ ]
341
+ )