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,403 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ from __future__ import annotations
4
+
5
+ import copy
6
+ import dataclasses
7
+ import logging
8
+ from typing import Dict, Mapping, Optional, Sequence, Set
9
+
10
+ import onnx
11
+ import onnx.defs
12
+
13
+ import onnxscript
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ _ONNX_DTYPE_TO_ONNX_TENSOR_TYPE_STR: Mapping[int, str] = {
18
+ onnx.TensorProto.FLOAT: "tensor(float)",
19
+ onnx.TensorProto.UINT8: "tensor(uint8)",
20
+ onnx.TensorProto.INT8: "tensor(int8)",
21
+ onnx.TensorProto.UINT16: "tensor(uint16)",
22
+ onnx.TensorProto.INT16: "tensor(int16)",
23
+ onnx.TensorProto.INT32: "tensor(int32)",
24
+ onnx.TensorProto.INT64: "tensor(int64)",
25
+ onnx.TensorProto.STRING: "tensor(string)",
26
+ onnx.TensorProto.BOOL: "tensor(bool)",
27
+ onnx.TensorProto.FLOAT16: "tensor(float16)",
28
+ onnx.TensorProto.DOUBLE: "tensor(double)",
29
+ onnx.TensorProto.COMPLEX64: "tensor(complex64)",
30
+ onnx.TensorProto.COMPLEX128: "tensor(complex128)",
31
+ onnx.TensorProto.UINT32: "tensor(uint32)",
32
+ onnx.TensorProto.UINT64: "tensor(uint64)",
33
+ onnx.TensorProto.BFLOAT16: "tensor(bfloat16)",
34
+ }
35
+
36
+ _ONNX_ATTR_TYPE_TO_ONNX_TENSOR_TYPE_STR: Mapping[int, str] = {
37
+ onnx.AttributeProto.UNDEFINED: "undefined",
38
+ onnx.AttributeProto.FLOAT: "tensor(float)",
39
+ onnx.AttributeProto.INT: "tensor(int64)",
40
+ onnx.AttributeProto.STRING: "tensor(string)",
41
+ onnx.AttributeProto.FLOATS: "tensor(float)",
42
+ onnx.AttributeProto.INTS: "tensor(int64)",
43
+ }
44
+
45
+
46
+ class TypeConstraint:
47
+ """Type constraint shared by multiple values."""
48
+
49
+ name: str
50
+ type_strs: Set[str]
51
+ values: Set[Value]
52
+
53
+ def __init__(self, name: str, type_strs: Set[str]):
54
+ self.name = name
55
+ self.type_strs = type_strs
56
+ self.values = set()
57
+
58
+ def merge_type_constraint(self, other: TypeConstraint):
59
+ """Merge two type constraints.
60
+
61
+ Typically this process tightens the type constraints.
62
+
63
+ For example, consider two values with different existing type constraints:
64
+
65
+ input1: TypeConstraint(name="input1", type_strs={"tensor(float)", "tensor(int64)"})
66
+ input2: TypeConstraint(name="input2", type_strs={"tensor(float)", "tensor(int32)"})
67
+
68
+ Now consider they are two inputs to `Add` node, where the op schema is:
69
+
70
+ inputs: [T, T]
71
+ outputs: [T]
72
+ T: ['tensor(uint8)', ..., 'tensor(float)', 'tensor(int64)', 'tensor(int32)']
73
+
74
+ `input1` and `input2` must now bound to the same type constraint, hence the result is
75
+ the intersection of the two existing type constraints with the op schema type constraint:
76
+
77
+ input1: TypeConstraint(name="input1.input2", type_strs={"tensor(float)"})
78
+ input2: TypeConstraint(name="input1.input2", type_strs={"tensor(float)"})
79
+ """
80
+ if self is other:
81
+ return
82
+ self.type_strs.intersection_update(other.type_strs)
83
+ self.values = self.values.union(other.values)
84
+ for meta in self.values:
85
+ meta.type_constraint = self
86
+ self.name = f"{self.name}.{other.name}"
87
+
88
+ def bind_value(self, value: Value):
89
+ """Bind a value to this type constraint.
90
+
91
+ If the value does not have a type constraint, set it to this type constraint.
92
+ Otherwise, merge the two type constraints.
93
+ """
94
+ if value.type_constraint is not None:
95
+ self.merge_type_constraint(value.type_constraint)
96
+ else:
97
+ self.values.add(value)
98
+ value.type_constraint = self
99
+
100
+ def __repr__(self):
101
+ value_names = [value.name for value in self.values]
102
+ return f"TypeConstraint(name={self.name}, type_strs={self.type_strs}, values={value_names})"
103
+
104
+
105
+ class Value:
106
+ """Represents a value in the graph. Associated with a TypeConstraint."""
107
+
108
+ def __init__(self, name: str):
109
+ self.type_constraint: Optional[TypeConstraint] = None
110
+ self.name: str = name
111
+
112
+ def merge_type_constraint(self, other: Value):
113
+ if other.type_constraint is not None:
114
+ other.type_constraint.bind_value(self)
115
+ elif self.type_constraint is not None:
116
+ self.type_constraint.bind_value(other)
117
+ else:
118
+ raise ValueError(
119
+ f"Cannot merge two values without type constraints. {self} and {other}"
120
+ )
121
+
122
+ def __repr__(self) -> str:
123
+ return f"Value(name={self.name}, type_constraint={self.type_constraint})"
124
+
125
+
126
+ @dataclasses.dataclass
127
+ class OnnxFunctionTypeConstraints:
128
+ input_type_constraints: Dict[str, Optional[TypeConstraint]]
129
+ output_type_constraints: Dict[str, Optional[TypeConstraint]]
130
+ intermediate_type_constraints: Dict[str, Optional[TypeConstraint]]
131
+
132
+ def __repr__(self):
133
+ repr_strs = [
134
+ "Type Constraints:",
135
+ " Inputs: ",
136
+ ]
137
+ repr_strs += [
138
+ f" {name}: {type_constraint.name}"
139
+ if type_constraint is not None
140
+ else f" {name}: None"
141
+ for name, type_constraint in self.input_type_constraints.items()
142
+ ]
143
+ repr_strs += [
144
+ " Outputs: ",
145
+ ]
146
+ repr_strs += [
147
+ f" {name}: {type_constraint.name}"
148
+ if type_constraint is not None
149
+ else f" {name}: None"
150
+ for name, type_constraint in self.output_type_constraints.items()
151
+ ]
152
+ repr_strs += [
153
+ " Type Constraints: ",
154
+ ]
155
+ # Trick to get unique type constraints but maintain the order.
156
+ ordered_unique_type_constraints = dict.fromkeys(self.input_type_constraints.values())
157
+ ordered_unique_type_constraints.update(
158
+ dict.fromkeys(self.output_type_constraints.values())
159
+ )
160
+ repr_strs += [
161
+ f" {type_constraint.name}: {type_constraint.type_strs}"
162
+ for type_constraint in ordered_unique_type_constraints
163
+ if type_constraint is not None
164
+ ]
165
+
166
+ if self.intermediate_type_constraints:
167
+ repr_strs += [" Intermediate Values: "]
168
+ repr_strs += [
169
+ f" {name}: {type_constraint.name}"
170
+ if type_constraint is not None
171
+ else f" {name}: None"
172
+ for name, type_constraint in self.intermediate_type_constraints.items()
173
+ ]
174
+
175
+ repr_strs += [
176
+ " Intermediate Type Constraints: ",
177
+ ]
178
+ ordered_unique_type_constraints = dict.fromkeys(
179
+ self.intermediate_type_constraints.values()
180
+ )
181
+ repr_strs += [
182
+ f" {type_constraint.name}: {type_constraint.type_strs}"
183
+ for type_constraint in ordered_unique_type_constraints
184
+ if type_constraint is not None
185
+ ]
186
+
187
+ return "\n".join(repr_strs)
188
+
189
+
190
+ class TypeConstraintDeducer:
191
+ def __init__(self, onnx_function: onnxscript.OnnxFunction):
192
+ self.onnx_function = onnx_function
193
+ self.values: Dict[str, Value] = {}
194
+
195
+ def type_constraints(self, signature_only: bool = True) -> OnnxFunctionTypeConstraints:
196
+ """Retrieve deduced type constraints for the ONNX function."""
197
+ if not self.values:
198
+ raise ValueError("Must call deduce() first")
199
+
200
+ input_type_constraints = {
201
+ name: self.values[name].type_constraint for name in self.function_proto.input
202
+ }
203
+ output_type_constraints = {
204
+ name: self.values[name].type_constraint for name in self.function_proto.output
205
+ }
206
+ intermediate_type_constraints = (
207
+ {}
208
+ if signature_only
209
+ else {name: value.type_constraint for name, value in self.values.items()}
210
+ )
211
+
212
+ # Rename type constraints to T0, T1, T2, ...
213
+ seen_type_constraints: Set[TypeConstraint] = set()
214
+ for type_constraint in (
215
+ *input_type_constraints.values(),
216
+ *output_type_constraints.values(),
217
+ *intermediate_type_constraints.values(),
218
+ ):
219
+ if type_constraint is not None and type_constraint not in seen_type_constraints:
220
+ type_constraint.name = f"T{len(seen_type_constraints)}"
221
+ seen_type_constraints.add(type_constraint)
222
+
223
+ return OnnxFunctionTypeConstraints(
224
+ input_type_constraints, output_type_constraints, intermediate_type_constraints
225
+ )
226
+
227
+ def deduce(self, signature_only: bool = True) -> OnnxFunctionTypeConstraints:
228
+ """Deduce type constraints for all values in the graph.
229
+
230
+ Args:
231
+ signature_only: If True, return deduce type constraints only for function signature.
232
+ Otherwise, return deduced type constraints for all values in the graph.
233
+ """
234
+ self.values = {}
235
+ self.function_proto = self.onnx_function.to_function_proto()
236
+ self.opset_version = self.function_proto.opset_import[0].version
237
+
238
+ param_schemas = self.onnx_function.param_schemas()
239
+ for param_schema in param_schemas:
240
+ if param_schema.is_input:
241
+ self.values[param_schema.name] = Value(param_schema.name)
242
+
243
+ for node in self.function_proto.node:
244
+ self._process_node(node)
245
+
246
+ return self.type_constraints(signature_only)
247
+
248
+ def _bind_signature(
249
+ self,
250
+ node: onnx.NodeProto,
251
+ param_names: Sequence[str],
252
+ param_schemas: Sequence[onnx.defs.OpSchema.FormalParameter],
253
+ op_type_constraints: Dict[str, TypeConstraint],
254
+ is_output: bool = False,
255
+ ):
256
+ param_schemas = list(param_schemas)
257
+ # If the last parameter is variadic, duplicate it to match the number of parameters.
258
+ if (
259
+ len(param_schemas) < len(param_names)
260
+ and param_schemas[-1].option == onnx.defs.OpSchema.FormalParameterOption.Variadic
261
+ ):
262
+ param_schemas += [param_schemas[-1]] * (len(param_names) - len(param_schemas))
263
+ for name, schema in zip(param_names, param_schemas):
264
+ if is_output:
265
+ if name in self.values:
266
+ raise ValueError(f"Output {name} already exists.")
267
+ value = Value(name)
268
+ self.values[name] = value
269
+ else:
270
+ if not name:
271
+ # Skip optional inputs
272
+ continue
273
+ value = self.values[name]
274
+ if (new_type_constraint := op_type_constraints.get(schema.type_str)) is None:
275
+ # parameter is annotated with type string instead of type constraint.
276
+ # Create individual type constraint.
277
+ new_type_constraint = TypeConstraint(
278
+ name=f"T_{name}",
279
+ type_strs={schema.type_str},
280
+ )
281
+ if not schema.is_homogeneous:
282
+ # Parameter is not homogeneous, this appears with variadic parameters.
283
+ # Meaning the type constraint is not shared amongst them.
284
+ # Creating a type constraint copy.
285
+ new_type_constraint = TypeConstraint(
286
+ name=f"{schema.name}_{name}",
287
+ type_strs=new_type_constraint.type_strs,
288
+ )
289
+ prev_value_constraint = copy.deepcopy(value.type_constraint)
290
+ new_type_constraint.bind_value(value)
291
+ if prev_value_constraint is not None and len(
292
+ prev_value_constraint.type_strs
293
+ ) > len(new_type_constraint.type_strs):
294
+ logger.info(
295
+ "Type constraint is tightened due to binding %s with parameter %s in node %s(%s)",
296
+ value.name,
297
+ schema.name,
298
+ node.op_type,
299
+ node.name,
300
+ )
301
+ logger.info(" %s", prev_value_constraint.type_strs)
302
+ logger.info("->")
303
+ logger.info(" %s", new_type_constraint.type_strs)
304
+
305
+ def _perform_extra_type_constraint_tightening(self, node: onnx.NodeProto):
306
+ if node.op_type == "If":
307
+ # Step into subgraph for more type constraint deduction.
308
+ subgraph_attr_names = ("then_branch", "else_branch")
309
+ for attr in node.attribute:
310
+ if attr.name not in subgraph_attr_names:
311
+ continue
312
+ subgraph = attr.g
313
+ for subgraph_node in subgraph.node:
314
+ self._process_node(subgraph_node)
315
+ for subgraph_output, node_output_name in zip(subgraph.output, node.output):
316
+ # Type constraint must agree between "then" and "else" branch.
317
+ self.values[node_output_name].merge_type_constraint(
318
+ self.values[subgraph_output.name]
319
+ )
320
+ elif node.op_type in ("Loop", "Scan"):
321
+ # Step into subgraph for more type constraint deduction.
322
+ raise NotImplementedError("Loop/Scan is not supported yet!")
323
+ elif node.op_type == "Constant":
324
+ # Constant type is static and can be inferred from attribute.
325
+ # Tighten the type constraint.
326
+ tensor_attr = node.attribute[0]
327
+ type_constraint_name = f"Constant_{node.name}"
328
+ if tensor_attr.type == onnx.AttributeProto.TENSOR:
329
+ type_constraint = TypeConstraint(
330
+ type_constraint_name,
331
+ {_ONNX_DTYPE_TO_ONNX_TENSOR_TYPE_STR[tensor_attr.t.data_type]},
332
+ )
333
+ else:
334
+ type_constraint = TypeConstraint(
335
+ type_constraint_name,
336
+ {_ONNX_ATTR_TYPE_TO_ONNX_TENSOR_TYPE_STR[tensor_attr.type]},
337
+ )
338
+ type_constraint.bind_value(self.values[node.output[0]])
339
+ elif node.op_type == "Cast":
340
+ to_attr = node.attribute[0]
341
+ if not to_attr.ref_attr_name:
342
+ # Cast to a static type.
343
+ # Tighten the type constraint
344
+ type_constraint = TypeConstraint(
345
+ f"Cast_{node.name}",
346
+ {_ONNX_DTYPE_TO_ONNX_TENSOR_TYPE_STR[node.attribute[0].i]},
347
+ )
348
+ type_constraint.bind_value(self.values[node.output[0]])
349
+
350
+ def _process_node(self, node: onnx.NodeProto):
351
+ if node.domain and node.domain != "onnx":
352
+ raise NotImplementedError("Nested function is not supported yet.")
353
+
354
+ if node.op_type in ("Loop", "Scan"):
355
+ # Step into subgraph for more type constraint deduction.
356
+ raise NotImplementedError("Loop/Scan is not supported yet!")
357
+
358
+ # Creating new type constraints from op schema
359
+ op_schema = onnx.defs.get_schema(
360
+ node.op_type, max_inclusive_version=self.opset_version, domain=node.domain
361
+ )
362
+ op_type_constraints = {
363
+ ts.type_param_str: TypeConstraint(
364
+ name=f"{ts.type_param_str}_{node.name}", type_strs=set(ts.allowed_type_strs)
365
+ )
366
+ for ts in op_schema.type_constraints
367
+ }
368
+
369
+ # Binding new type constraints to input values.
370
+ self._bind_signature(node, node.input, op_schema.inputs, op_type_constraints)
371
+ # Creating new values for outputs, and bind with type constraints.
372
+ self._bind_signature(
373
+ node,
374
+ node.output,
375
+ op_schema.outputs,
376
+ op_type_constraints,
377
+ is_output=True,
378
+ )
379
+
380
+ # Postprocess a few special cases
381
+ self._perform_extra_type_constraint_tightening(node)
382
+
383
+
384
+ def deduce_type_constraints(
385
+ onnx_function: onnxscript.OnnxFunction, signature_only: bool = True
386
+ ) -> OnnxFunctionTypeConstraints:
387
+ """Deduce type constraints for an ONNX function.
388
+
389
+ * Expects Tensors to be pre-annotated as `TensorType`.
390
+ * Expects Attributes to be pre-annotated correctly.
391
+ * Produces the least strict type constraints allowed by deducing from OpSchema in FunctionProto.
392
+ * Produces explanation for type constraint tightening.
393
+ * `TracedOnnxFunction` is not planned.
394
+
395
+ Args:
396
+ onnx_function: ONNX function to generate type constraints for.
397
+ signature_only: Whether to only generate type constraints for the function signature.
398
+
399
+ Returns:
400
+ Type constraints for the ONNX function.
401
+ """
402
+ logger.info("Deducing type constraints for %s", onnx_function.name)
403
+ return TypeConstraintDeducer(onnx_function).deduce(signature_only=signature_only)