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,250 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING, Any, Callable, Optional, Sequence
7
+
8
+ import numpy as np
9
+ import onnx
10
+ from onnx import helper, numpy_helper
11
+ from onnx.defs import OpSchema
12
+
13
+ from onnxscript import tensor
14
+
15
+ if TYPE_CHECKING:
16
+ from onnxscript import converter
17
+
18
+ # Conversions from python values to ONNX are used by both the script converter as well
19
+ # as the eager-mode runtime and both need to be consistent. The script converter converts
20
+ # python values into ONNX TensorProto, while the runtime converts python values into
21
+ # ONNXScript runtime's value-representation (based on Tensor).
22
+
23
+
24
+ # Utilities to convert a python value to TensorProto (for use by the script converter)
25
+
26
+
27
+ def _py_type_to_onnx_type(pytype: type):
28
+ if pytype is bool:
29
+ return onnx.TensorProto.BOOL
30
+ if pytype is int:
31
+ return onnx.TensorProto.INT64
32
+ if pytype is float:
33
+ return onnx.TensorProto.FLOAT
34
+ if pytype is str:
35
+ return onnx.TensorProto.STRING
36
+ raise ValueError(f"Tensor element of type {pytype} not supported")
37
+
38
+
39
+ def pyvalue_to_onnx_tensor(tensor_name: str, pyvalue):
40
+ if isinstance(pyvalue, np.ndarray):
41
+ return numpy_helper.from_array(pyvalue, tensor_name)
42
+ if isinstance(pyvalue, list):
43
+ if len(pyvalue) == 0:
44
+ raise ValueError("Cannot convert an empty list to tensor")
45
+ pytype = type(pyvalue[0])
46
+ if not all(isinstance(e, pytype) for e in pyvalue):
47
+ raise ValueError(
48
+ "Cannot convert an list with elements of different types to tensor"
49
+ )
50
+ return helper.make_tensor(
51
+ tensor_name,
52
+ _py_type_to_onnx_type(pytype),
53
+ [len(pyvalue)],
54
+ pyvalue,
55
+ )
56
+ onnx_type = _py_type_to_onnx_type(type(pyvalue))
57
+ if onnx_type is onnx.TensorProto.BOOL:
58
+ return helper.make_tensor(tensor_name, onnx_type, [], [int(pyvalue)])
59
+ if onnx_type is onnx.TensorProto.STRING:
60
+ return helper.make_tensor(tensor_name, onnx_type, [], vals=[pyvalue.encode("utf-8")])
61
+
62
+ return helper.make_tensor(tensor_name, onnx_type, [], [pyvalue])
63
+
64
+
65
+ _REPEATED_ATTRIBUTE_TYPES = frozenset(
66
+ {
67
+ onnx.AttributeProto.FLOATS,
68
+ onnx.AttributeProto.INTS,
69
+ onnx.AttributeProto.STRINGS,
70
+ onnx.AttributeProto.TENSORS,
71
+ onnx.AttributeProto.GRAPHS,
72
+ onnx.AttributeProto.SPARSE_TENSORS,
73
+ onnx.AttributeProto.TYPE_PROTOS,
74
+ }
75
+ )
76
+
77
+
78
+ def pyvalue_to_onnx_attribute(
79
+ key: str,
80
+ value: Any,
81
+ name_generator: Callable[[], str],
82
+ attr_type: Optional[onnx.AttributeProto.AttributeType] = None,
83
+ ) -> onnx.AttributeProto:
84
+ """Helper function to create an ONNX AttributeProto.
85
+
86
+ This is a refinement of onnx.helper.make_attribute that works with ONNX Script
87
+ conventions for allowed types for attribute-values. In particular, it allows
88
+ * Empty lists as attribute values, provided the attribute type is specified
89
+ and is a list type.
90
+ * Scalar-values like 1.0 as well as lists like [1, -1] to be specified
91
+ when the attribute type is TensorProto by automatically converting the value
92
+ into a 0-D or 1-D tensor respectively.
93
+ """
94
+ if isinstance(value, list) and not value:
95
+ # Empty list value:
96
+ if attr_type is None:
97
+ raise ValueError("Attribute type must be specified for empty list value.")
98
+ if attr_type not in _REPEATED_ATTRIBUTE_TYPES:
99
+ raise ValueError("Empty list value is only allowed for repeated attribute types.")
100
+ return onnx.AttributeProto(name=key, type=attr_type)
101
+ elif attr_type == onnx.AttributeProto.TENSOR and not isinstance(value, onnx.TensorProto):
102
+ return onnx.AttributeProto(
103
+ name=key, type=attr_type, t=pyvalue_to_onnx_tensor(name_generator(), value)
104
+ )
105
+ else:
106
+ return onnx.helper.make_attribute(key, value)
107
+
108
+
109
+ # Utilities to convert python values into onnxscript tensors.
110
+
111
+
112
+ def _promotable(x) -> bool:
113
+ """Checks if a runtime parameter value needs to be promoted into an onnxscript value.
114
+ This is the runtime-equivalent of the promotion of literal constants into ONNX values
115
+ in the static converter.
116
+ """
117
+ if isinstance(x, (bool, int, float)):
118
+ return True
119
+ if isinstance(x, list) and x:
120
+ # Note: This is meant to handle valid scenarios correctly. No attempt is
121
+ # made yet to capture all invalid usages in runtime mode.
122
+ return _promotable(x[0])
123
+ return False
124
+
125
+
126
+ def _get_dtype(pyvalue):
127
+ """Return np.dtype to use when converting a python value to an onnxscript tensor.
128
+ Note that int constants are treated as int64, as that is the common type in ONNX
129
+ for shape/index values.
130
+ """
131
+ if isinstance(pyvalue, bool):
132
+ return np.bool_
133
+ elif isinstance(pyvalue, int):
134
+ return np.int64
135
+ elif isinstance(pyvalue, float):
136
+ return np.float32
137
+ elif isinstance(pyvalue, list):
138
+ if pyvalue:
139
+ # TODO: What to do about lists with mixed value types, like [1, 2.0]?
140
+ # Should at least produce an error/warning message.
141
+ return _get_dtype(pyvalue[0])
142
+ raise ValueError("Cannot determine target type for empty list")
143
+ raise TypeError(f"Value of unexpected type {type(pyvalue)}")
144
+
145
+
146
+ def cast_pyvalue_to_os_tensor(pyvalue, dtype=None):
147
+ """Promotes python values into onnxscript tensors.
148
+ The optional argument dtype specifies the desired np.dtype of the tensor,
149
+ used only when a non-standard onnxscript-value is promoted into one.
150
+ """
151
+ if _promotable(pyvalue):
152
+ if dtype is None:
153
+ dtype = _get_dtype(pyvalue)
154
+ return tensor.Tensor(np.array(pyvalue, dtype=dtype))
155
+ return pyvalue
156
+
157
+
158
+ def cast_inputs(
159
+ get_type_info: Callable[[Any], Any],
160
+ cast: Callable[[Any, Any], Any],
161
+ op_schema: OpSchema | None,
162
+ args,
163
+ ) -> tuple[Any, ...]:
164
+ """Uses schema specification to support a limited form of auto-casting.
165
+
166
+ * Scalars are promoted to tensors.
167
+ * Further. they are cast to the required type when used in ops with other
168
+ tensor inputs that are required to be of same type.
169
+ Thus, in "A+1" or "Add(A, 1)", the value 1 will be converted to the same
170
+ type as A.
171
+
172
+ This is used by the converter in a static-mode, as well as by the eager-mode
173
+ execution in a dynamic-mode.
174
+ """
175
+ if op_schema is None:
176
+ # Either an error or a custom op.
177
+ # No checks/casts in this case.
178
+ return tuple(cast(x, None) for x in args)
179
+
180
+ expected_inputs = op_schema.inputs
181
+ # We make two passes. In the first pass, we identify known type-bindings for
182
+ # type-variables: eg., {'T1' : np.float32, 'T2' : np.int32}.
183
+ # In the second pass, we use these bindings to cast scalar-values to
184
+ # tensors of appropriate types. The two passes are needed to handle cases
185
+ # like "Add(1, X)" where 1 must be cast to the same type as X.
186
+ type_bindings: dict[Optional[str], np.dtype] = {}
187
+ args_typevars: list[tuple[str, Optional[str]]] = []
188
+ for i, x in enumerate(args):
189
+ if i < len(expected_inputs):
190
+ expected = expected_inputs[i]
191
+ elif expected_inputs[-1].option == OpSchema.FormalParameterOption.Variadic:
192
+ expected = expected_inputs[-1]
193
+ if not expected.is_homogeneous:
194
+ args_typevars.append((x, None))
195
+ continue
196
+ else:
197
+ raise ValueError(
198
+ f"Number of actual parameters {len(args)} "
199
+ f"exceeds number of formal parameters {len(expected_inputs)}."
200
+ )
201
+ typevar = expected.type_str
202
+ if "(" not in typevar:
203
+ # typevar is an identifier, like "T"
204
+ typeinfo = get_type_info(x)
205
+ if typeinfo is not None:
206
+ type_bindings[typevar] = typeinfo
207
+ args_typevars.append((x, typevar))
208
+ cast_args = [cast(x, type_bindings.get(typevar)) for x, typevar in args_typevars]
209
+ return tuple(cast_args)
210
+
211
+
212
+ def dynamic_cast_inputs(op_schema: OpSchema, args):
213
+ """Used for autocast during eager-mode execution."""
214
+
215
+ def get_type_info(x):
216
+ return x.dtype if isinstance(x, tensor.Tensor) else None
217
+
218
+ return cast_inputs(get_type_info, cast_pyvalue_to_os_tensor, op_schema, args)
219
+
220
+
221
+ def static_cast_inputs(
222
+ converter_: converter.Converter,
223
+ op_schema: Optional[OpSchema],
224
+ args: Sequence[Optional[converter.Variable]],
225
+ ) -> tuple[str, ...]:
226
+ """Used for autocast during script-translation.
227
+ This is meant to transform expressions like "Add(X, 1)" to "Add(X, CastLike(1, X))"
228
+ Polymorphic constants (like 0 and 1) are cast to the type of other operands as needed.
229
+ """
230
+
231
+ def get_type_info(x: Optional[converter.Variable]) -> Optional[converter.Variable]:
232
+ """Returns x back if x can serve as the target-type for a cast (as the second
233
+ argument of CastLike) and None otherwise. In the expression "Add(X, 1), 1 is
234
+ castable, while X can serve as the target-type.
235
+ """
236
+ return None if x is None or x.is_castable else x
237
+
238
+ def cast_like(
239
+ x: Optional[converter.Variable], y: Optional[converter.Variable]
240
+ ) -> Optional[str]:
241
+ if x is None:
242
+ return None
243
+ if x.is_castable and y is not None:
244
+ # Polymorphic constant x is cast to the type of y:
245
+ x_cast = converter_.generate_unique_name(f"{x.name}_cast")
246
+ converter_.emit([x_cast], "CastLike", [x.name, y.name])
247
+ return x_cast
248
+ return x.name
249
+
250
+ return cast_inputs(get_type_info, cast_like, op_schema, args)
@@ -0,0 +1,78 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """Utility for deprecating APIs."""
4
+
5
+ # Reference: https://github.com/pytorch/pytorch/blob/aed9bee0413dac190452fbfa9ab2a44b6e6843f5/torch/onnx/_deprecation.py
6
+
7
+ import functools
8
+ import textwrap
9
+ import warnings
10
+ from typing import Callable, TypeVar
11
+
12
+ T = TypeVar("T")
13
+
14
+
15
+ @functools.lru_cache(maxsize=1024)
16
+ def _warn_once(message: str):
17
+ """Issue a FutureWarning only once per message."""
18
+ warnings.warn(message, category=FutureWarning, stacklevel=3)
19
+
20
+
21
+ def deprecated(since: str, removed_in: str, instructions: str) -> Callable[[T], T]:
22
+ """Marks functions as deprecated.
23
+
24
+ It will result in a warning when the function is called and a note in the
25
+ docstring.
26
+
27
+ Args:
28
+ since: The version when the function was first deprecated.
29
+ removed_in: The version when the function will be removed.
30
+ instructions: The action users should take.
31
+
32
+ Returns:
33
+ A decorator that can be used to mark functions as deprecated.
34
+ """
35
+
36
+ def decorator(function):
37
+ @functools.wraps(function)
38
+ def wrapper(*args, **kwargs):
39
+ _warn_once(
40
+ f"'{function.__module__}.{function.__qualname__}' "
41
+ f"is deprecated in version {since} and will be "
42
+ f"removed in {removed_in}. Please {instructions}.",
43
+ )
44
+ return function(*args, **kwargs)
45
+
46
+ # Add a deprecation note to the docstring.
47
+ docstring = function.__doc__ or ""
48
+
49
+ # Add a note to the docstring.
50
+ deprecation_note = textwrap.dedent(
51
+ f"""\
52
+ .. deprecated:: {since}
53
+ Deprecated and will be removed in version {removed_in}.
54
+ Please {instructions}.
55
+ """
56
+ )
57
+
58
+ # Split docstring at first occurrence of newline
59
+ summary_and_body = docstring.split("\n\n", 1)
60
+
61
+ if len(summary_and_body) > 1:
62
+ summary, body = summary_and_body
63
+
64
+ # Dedent the body. We cannot do this with the presence of the summary because
65
+ # the body contains leading whitespaces when the summary does not.
66
+ body = textwrap.dedent(body)
67
+
68
+ new_docstring_parts = [deprecation_note, "\n\n", summary, body]
69
+ else:
70
+ summary = summary_and_body[0]
71
+
72
+ new_docstring_parts = [deprecation_note, "\n\n", summary]
73
+
74
+ wrapper.__doc__ = "".join(new_docstring_parts)
75
+
76
+ return wrapper
77
+
78
+ return decorator
@@ -0,0 +1,148 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """Function for manipulating input parameters of an Op or a OnnxFunction."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import collections
8
+ from typing import Any, OrderedDict, Sequence
9
+
10
+ from onnxscript import values
11
+
12
+
13
+ def separate_input_attributes_from_arguments(
14
+ param_schemas: Sequence[values.ParamSchema],
15
+ args,
16
+ kwargs,
17
+ fill_defaults: bool = True,
18
+ allow_extra_kwargs: bool = False,
19
+ ) -> tuple[list[Any], OrderedDict[str, Any]]:
20
+ """Separate Python args and kwargs into ONNX inputs and attributes.
21
+
22
+ Args:
23
+ param_schemas: The parameter schemas of an Op or a OnnxFunction.
24
+ args: The Python positional arguments supplied by the caller.
25
+ kwargs: The Python keyword arguments supplied by the caller.
26
+ fill_defaults: Whether to fill the default values for attributes.
27
+ allow_extra_kwargs: Whether to allow extra keyword arguments.
28
+ When set to True, extra/unknown arguments will be ignored.
29
+
30
+ Returns:
31
+ A tuple of two elements:
32
+ - A list of ONNX inputs.
33
+ - An ordered dictionary of ONNX attribute names and values.
34
+
35
+ Raises:
36
+ TypeError: When allow_extra_kwargs is False and there are unknown kwargs.
37
+ TypeError: When a required input is not provided.
38
+ """
39
+ # args, kwargs and param_schemas should be all in order
40
+ # user may not specify all inputs or attributes
41
+
42
+ all_param_names = {param.name for param in param_schemas}
43
+ extra_kwargs = set(kwargs).difference(all_param_names)
44
+ if extra_kwargs and not allow_extra_kwargs:
45
+ raise TypeError(f"Unexpected keyword arguments '{extra_kwargs}'")
46
+
47
+ onnx_inputs = []
48
+ onnx_attributes = collections.OrderedDict()
49
+
50
+ for i, param in enumerate(param_schemas):
51
+ if param.is_variadic_input:
52
+ # Exhaust all remaining args
53
+ onnx_inputs.extend(args[i:])
54
+ args = []
55
+ continue
56
+ if i < len(args):
57
+ if param.is_input:
58
+ onnx_inputs.append(args[i])
59
+ else:
60
+ onnx_attributes[param.name] = args[i]
61
+ elif param.name in kwargs:
62
+ if param.is_input:
63
+ onnx_inputs.append(kwargs[param.name])
64
+ else:
65
+ onnx_attributes[param.name] = kwargs[param.name]
66
+ elif (
67
+ param.is_attribute and param.default is not values._EmptyDefault # pylint: disable=protected-access
68
+ ):
69
+ # User did not provide the attribute
70
+ if fill_defaults:
71
+ onnx_attributes[param.name] = param.default
72
+ elif param.required:
73
+ raise TypeError(f"Required input '{param}' was not provided")
74
+
75
+ return onnx_inputs, onnx_attributes
76
+
77
+
78
+ def tag_arguments_with_param_schemas(
79
+ param_schemas: Sequence[values.ParamSchema],
80
+ args,
81
+ kwargs,
82
+ fill_defaults: bool = True,
83
+ allow_extra_kwargs: bool = False,
84
+ ) -> tuple[list[tuple[Any, values.ParamSchema]], dict[str, tuple[Any, values.ParamSchema]]]:
85
+ """Tag Python args and kwargs with matching ONNX ParamSchema.
86
+
87
+ Args:
88
+ param_schemas: The parameter schemas of an Op or a OnnxFunction.
89
+ args: The Python positional arguments supplied by the caller.
90
+ kwargs: The Python keyword arguments supplied by the caller.
91
+ fill_defaults: Whether to fill the default values for attributes.
92
+ allow_extra_kwargs: Whether to allow extra keyword arguments.
93
+ When set to True, extra/unknown arguments will be ignored.
94
+
95
+ Returns:
96
+ A tuple of two elements:
97
+ - A list of tuple of Python positional argument and ParamSchema.
98
+ - An ordered dictionary of Python keyword argument names and tuple of argument
99
+ value and ParamSchema.
100
+
101
+ Raises:
102
+ TypeError: When allow_extra_kwargs is False and there are unknown kwargs.
103
+ TypeError: When a required input is not provided.
104
+ """
105
+ # args, kwargs and param_schemas should be all in order
106
+ # user may not specify all inputs or attributes
107
+
108
+ all_param_names = {param.name for param in param_schemas}
109
+ extra_kwargs = set(kwargs).difference(all_param_names)
110
+ if extra_kwargs and not allow_extra_kwargs:
111
+ raise TypeError(f"Unexpected keyword arguments '{extra_kwargs}'")
112
+
113
+ tagged_args: list[tuple[Any, values.ParamSchema]] = []
114
+ tagged_kwargs: dict[str, tuple[Any, values.ParamSchema]] = {}
115
+
116
+ for i, param in enumerate(param_schemas):
117
+ if param.is_variadic_input:
118
+ # Exhaust all remaining args
119
+ tagged_args.extend((arg, param) for arg in args[i:])
120
+ args = []
121
+ continue
122
+ if i < len(args):
123
+ tagged_args.append((args[i], param))
124
+ elif param.name in kwargs:
125
+ tagged_kwargs[param.name] = (kwargs[param.name], param)
126
+ elif param.default is not values._EmptyDefault: # pylint: disable=protected-access
127
+ # User did not provide the input/attribute
128
+ if fill_defaults:
129
+ tagged_kwargs[param.name] = (param.default, param)
130
+ elif param.required:
131
+ raise TypeError(f"Required input/attribute '{param}' was not provided")
132
+
133
+ return tagged_args, tagged_kwargs
134
+
135
+
136
+ def turn_to_kwargs_to_avoid_ordering(
137
+ param_schemas: Sequence[values.ParamSchema],
138
+ inputs: list[Any],
139
+ attributes: dict[str, Any],
140
+ ) -> dict[str, Any]:
141
+ """Return the inputs and attributes to the order of the function signature."""
142
+ for idx, param in enumerate(param_schemas):
143
+ if param.name not in attributes:
144
+ if param.is_variadic_input:
145
+ attributes[param.name] = inputs[idx:]
146
+ elif inputs:
147
+ attributes[param.name] = inputs.pop(0)
148
+ return attributes
@@ -0,0 +1,43 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """An internal wrapper for the beartype library.
4
+
5
+ Decorate a function with `@runtime_typing.checked` to enable runtime
6
+ type checking. The decorator is a no-op when the `beartype` library is not
7
+ installed.
8
+ """
9
+
10
+ import typing
11
+ import warnings
12
+
13
+ __all__ = [
14
+ "checked",
15
+ ]
16
+
17
+ T = typing.TypeVar("T", bound=typing.Callable[..., typing.Any])
18
+
19
+ try:
20
+ from beartype import beartype as _beartype_decorator
21
+ from beartype import roar as _roar
22
+
23
+ checked = typing.cast(typing.Callable[[T], T], _beartype_decorator)
24
+
25
+ # Beartype warns when we import from typing because the types are deprecated
26
+ # in Python 3.9. But there will be a long time until we can move to using
27
+ # the native container types for type annotations (when 3.9 is the lowest
28
+ # supported version). So we silence the warning.
29
+ warnings.filterwarnings(
30
+ "ignore",
31
+ category=_roar.BeartypeDecorHintPep585DeprecationWarning,
32
+ )
33
+ except ImportError:
34
+
35
+ def checked(func: T) -> T: # type: ignore[no-redef]
36
+ return func
37
+
38
+ except Exception as e: # pylint: disable=broad-exception-caught
39
+ # Warn errors that are not import errors (unexpected).
40
+ warnings.warn(f"{e}", stacklevel=2)
41
+
42
+ def checked(func: T) -> T: # type: ignore[no-redef]
43
+ return func
@@ -0,0 +1,99 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ from __future__ import annotations
4
+
5
+ import numbers
6
+ from typing import Optional, Sequence
7
+
8
+ import numpy as np
9
+ import onnx
10
+ import onnx.helper
11
+
12
+ from onnxscript import tensor
13
+
14
+
15
+ def external_tensor(
16
+ name: str,
17
+ data_type: int,
18
+ dims: Sequence[int],
19
+ location: str,
20
+ offset: Optional[int] = None,
21
+ length: Optional[int] = None,
22
+ checksum: Optional[str] = None,
23
+ basepath: Optional[str] = None,
24
+ ) -> onnx.TensorProto:
25
+ """Create a TensorProto referencing externally stored tensor-data.
26
+
27
+ Args:
28
+ name: name of the tensor
29
+ data_type: data type of tensor element
30
+ dims: shape of the tensor
31
+ location: location of the external file (relative path)
32
+ offset: offset in the file where the tensor-data starts
33
+ length: number of bytes containing the data
34
+ checksum: SHA1 digest of the file
35
+ basepath: basepath combined with location to form the full path
36
+
37
+ Returns:
38
+ TensorProto
39
+
40
+ See https://github.com/onnx/onnx/blob/main/docs/ExternalData.md for more details.
41
+ """
42
+ tensor_proto = onnx.TensorProto()
43
+ tensor_proto.name = name
44
+ tensor_proto.data_type = data_type
45
+ tensor_proto.dims.extend(dims)
46
+ tensor_proto.data_location = onnx.TensorProto.EXTERNAL
47
+
48
+ def add(k, v):
49
+ entry = tensor_proto.external_data.add()
50
+ entry.key = k
51
+ entry.value = str(v)
52
+
53
+ add("location", location)
54
+ if offset is not None:
55
+ add("offset", int(offset))
56
+ if length is not None:
57
+ add("length", int(length))
58
+ if checksum is not None:
59
+ add("checksum", checksum)
60
+ if basepath is not None:
61
+ add("basepath", basepath)
62
+ return tensor_proto
63
+
64
+
65
+ def value_to_type_proto(val):
66
+ """Return the ONNX type of a python-value."""
67
+ if isinstance(val, (np.ndarray, tensor.Tensor)):
68
+ elem_type = onnx.helper.np_dtype_to_tensor_dtype(val.dtype)
69
+ shape = val.shape
70
+ return onnx.helper.make_tensor_type_proto(elem_type, shape)
71
+ if isinstance(val, int):
72
+ return onnx.helper.make_tensor_type_proto(onnx.TensorProto.INT32, [])
73
+ if isinstance(val, (float, np.float32)):
74
+ return onnx.helper.make_tensor_type_proto(onnx.TensorProto.FLOAT, [])
75
+ if isinstance(val, list):
76
+ if len(val) > 0:
77
+ return onnx.helper.make_sequence_type_proto(value_to_type_proto(val[0]))
78
+ # Edge-case. Cannot determine a suitable ONNX type for an empty list.
79
+ # Should be using a typed-value instead.
80
+ # Treated as a sequence of tensors of float-type.
81
+ return onnx.helper.make_sequence_type_proto(
82
+ onnx.helper.make_tensor_type_proto(onnx.TensorProto.FLOAT, None)
83
+ )
84
+ if isinstance(val, numbers.Number):
85
+ nparray = np.array(val)
86
+ elem_type = onnx.helper.np_dtype_to_tensor_dtype(nparray.dtype)
87
+ return onnx.helper.make_tensor_type_proto(elem_type, [])
88
+ raise ValueError(f"Value of type {type(val)} is invalid as an ONNX input/output.")
89
+
90
+
91
+ def values_to_value_infos(name_values):
92
+ """Create a list of ValueInfoProto from a list of (name, value) pairs,
93
+ skipping any None values.
94
+ """
95
+ return [
96
+ onnx.helper.make_value_info(name, value_to_type_proto(val))
97
+ for (name, val) in name_values
98
+ if val is not None
99
+ ]