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,287 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ from __future__ import annotations
4
+
5
+ from typing import ClassVar
6
+
7
+ import onnx.numpy_helper
8
+
9
+ import onnxscript.ir as ir
10
+ import onnxscript.rewriter._ir_utils as ir_utils
11
+ import onnxscript.rewriter.no_op as no_op
12
+ import onnxscript.rewriter.pattern as orp
13
+
14
+
15
+ class CastIdentity(orp.RewriteRuleAsClass):
16
+ """Replaces ``Cast(., to=to)`` by ``Identity`` if possible."""
17
+
18
+ @classmethod
19
+ def pattern(cls, op, x, to):
20
+ return op.Cast(x, to=to)
21
+
22
+ @classmethod
23
+ def rewrite(cls, op, x: ir.Value, to: ir.Attr):
24
+ return op.Identity(x)
25
+
26
+ @classmethod
27
+ def check(cls, context, x, to) -> bool:
28
+ return x.dtype == to.value
29
+
30
+
31
+ class CastCast(orp.RewriteRuleAsClass):
32
+ """Replaces ``Cast(Cast(X, ...), to=to)`` by ``Cast(X, to=to)``."""
33
+
34
+ _allowed_tensor_types: ClassVar = {
35
+ onnx.TensorProto.FLOAT,
36
+ onnx.TensorProto.FLOAT16,
37
+ onnx.TensorProto.BFLOAT16,
38
+ onnx.TensorProto.DOUBLE,
39
+ }
40
+
41
+ @classmethod
42
+ def pattern(cls, op, x, to, to_ignored):
43
+ return op.Cast(op.Cast(x, to=to_ignored), to=to)
44
+
45
+ @classmethod
46
+ def check(cls, context, x: ir.Value, to: ir.Attr, to_ignored: ir.Attr) -> bool:
47
+ return (
48
+ to.value in cls._allowed_tensor_types
49
+ and to_ignored.value in cls._allowed_tensor_types
50
+ )
51
+
52
+ @classmethod
53
+ def rewrite(cls, op, x: ir.Value, to: ir.Attr, to_ignored: ir.Attr):
54
+ return op.Cast(x, to=to)
55
+
56
+
57
+ class ExpandIdentity(orp.RewriteRuleAsClass):
58
+ """Replaces ``Expand(..., shape)`` by ``Identity`` if possible."""
59
+
60
+ @classmethod
61
+ def pattern(cls, op, x, shape):
62
+ return op.Expand(x, shape)
63
+
64
+ @classmethod
65
+ def rewrite(cls, op, x: ir.Value, shape: ir.Value):
66
+ return op.Identity(x)
67
+
68
+ @classmethod
69
+ def check(cls, context, x, shape) -> bool:
70
+ if shape.const_value is None:
71
+ # Shape is not a constant and cannot be guessed.
72
+ return False
73
+ if (x_shape := x.shape) is None:
74
+ # We don't know the shape of the input
75
+ return False
76
+ return x_shape.dims == tuple(shape.const_value.numpy().tolist())
77
+
78
+
79
+ class ReshapeReshape(orp.RewriteRuleAsClass):
80
+ """Replaces ``Reshape(Reshape(X, ...), shape)`` by ``Reshape(X, shape)``.
81
+ The pattern matches only if second reshape reshapes into a shape
82
+ with positive values.
83
+ """
84
+
85
+ @classmethod
86
+ def pattern(cls, op, x, shape_ignored, shape):
87
+ return op.Reshape(op.Reshape(x, shape_ignored), shape)
88
+
89
+ @classmethod
90
+ def rewrite(cls, op, x: ir.Value, shape_ignored: ir.Value, shape: ir.Value):
91
+ return op.Reshape(x, shape)
92
+
93
+ @classmethod
94
+ def check(cls, context, x, shape_ignored, shape) -> bool:
95
+ if shape_ignored.const_value is None or shape.const_value is None:
96
+ return False
97
+ if shape.const_value.numpy().min() <= 0:
98
+ return False
99
+ return True
100
+
101
+
102
+ class SlicesSplit(orp.RewriteRuleAsClass):
103
+ """Replaces ``Slice(x, ...), Slice(x, ...)``
104
+ by ``Split(x, ...)`` if possible.
105
+ """
106
+
107
+ @classmethod
108
+ def pattern(cls, op, x, begin0, end0, axes0, begin1, end1, axes1):
109
+ return op.Slice(x, begin0, end0, axes0), op.Slice(x, begin1, end1, axes1)
110
+
111
+ @classmethod
112
+ def check(cls, context, x, begin0, end0, axes0, begin1, end1, axes1) -> bool:
113
+ if (
114
+ axes0.const_value is None
115
+ or axes1.const_value is None
116
+ or axes0.const_value.numpy().tolist() != axes1.const_value.numpy().tolist()
117
+ ):
118
+ return False
119
+ axes = axes0.const_value.numpy().tolist()
120
+ if len(axes) != 1:
121
+ return False
122
+ if x.shape:
123
+ rk = len(x.shape)
124
+ else:
125
+ rk = x.rank
126
+ if axes[0] != -1 and axes[0] != rk - 1:
127
+ return False
128
+ if (
129
+ begin0.const_value is None
130
+ or end0.const_value is None
131
+ or begin1.const_value is None
132
+ or end1.const_value is None
133
+ ):
134
+ return False
135
+ if begin0.const_value.numpy().tolist() != [0]:
136
+ return False
137
+ e0, b1, e1 = (
138
+ end0.const_value.numpy().tolist(),
139
+ begin1.const_value.numpy().tolist(),
140
+ end1.const_value.numpy().tolist(),
141
+ )
142
+ if e0[0] != b1[0]:
143
+ return False
144
+ shape = x.shape
145
+ if shape is None:
146
+ return False
147
+ last_dim = shape[-1]
148
+ if not isinstance(last_dim, int):
149
+ return False
150
+ if last_dim != e1[0]:
151
+ return False
152
+ if last_dim // 2 != b1[0]:
153
+ return False
154
+ return True
155
+
156
+ @classmethod
157
+ def rewrite(cls, op, x, begin0, end0, axes0, begin1, end1, axes1):
158
+ return op.Split(x, num_outputs=2, axis=-1, _outputs=2)
159
+
160
+
161
+ class TransposeIdentity(orp.RewriteRuleAsClass):
162
+ """Replaces ``Transpose(. perm=perm)``
163
+ when the permutation is identity.
164
+ """
165
+
166
+ @classmethod
167
+ def pattern(cls, op, x, perm):
168
+ return op.Transpose(x, perm=perm)
169
+
170
+ @classmethod
171
+ def check(cls, context, x: ir.Value, perm: ir.Attr) -> bool:
172
+ if isinstance(perm, ir.RefAttr):
173
+ return False
174
+ if perm.type == ir.AttributeType.INTS:
175
+ if perm.value == list(range(len(perm.value))):
176
+ return True
177
+ return False
178
+
179
+ @classmethod
180
+ def rewrite(cls, op, x: ir.Value, perm: ir.Attr):
181
+ return op.Identity(x)
182
+
183
+
184
+ class TransposeTranspose(orp.RewriteRuleAsClass):
185
+ """Replaces ``Transpose(Transpose(., perm=perm1), perm=perm2)``
186
+ when both permutations are inverse.
187
+ """
188
+
189
+ @classmethod
190
+ def pattern(cls, op, x, perm1, perm2):
191
+ return op.Transpose(op.Transpose(x, perm=perm1), perm=perm2)
192
+
193
+ @classmethod
194
+ def check(cls, context, x: ir.Value, perm1: ir.Attr, perm2: ir.Attr) -> bool:
195
+ if isinstance(perm1, ir.RefAttr) or isinstance(perm2, ir.RefAttr):
196
+ return False
197
+ return True
198
+
199
+ @classmethod
200
+ def _apply_transpose(cls, perm: tuple[int, ...], on: list[int]) -> list[int]:
201
+ assert len(perm) == len(on), "length mismatch"
202
+ res = [-1 for i in on]
203
+ for i, p in enumerate(perm):
204
+ res[i] = on[p]
205
+ return res
206
+
207
+ @classmethod
208
+ def _apply_transposes(
209
+ cls, perms: list[tuple[int, ...]], on: list[int] | None = None
210
+ ) -> list[int]:
211
+ if on is None:
212
+ on = list(range(len(perms[0])))
213
+ for p in perms:
214
+ on = cls._apply_transpose(p, on)
215
+ return on
216
+
217
+ @classmethod
218
+ def rewrite(cls, op, x: ir.Value, perm1: ir.Attr, perm2: ir.Attr):
219
+ first = list(range(len(perm1.value)))
220
+ last = cls._apply_transposes([perm1.value, perm2.value])
221
+ if first == last:
222
+ return op.Identity(x)
223
+ return op.Transpose(x, perm=last)
224
+
225
+
226
+ class UnsqueezeUnsqueeze(orp.RewriteRuleAsClass):
227
+ """Replaces ``Unsqueeze(Unsqueeze(., axes1), axes2)`` with one Unsqueeze."""
228
+
229
+ @classmethod
230
+ def pattern(cls, op, x, axes1, axes2):
231
+ return op.Unsqueeze(op.Unsqueeze(x, axes1), axes2)
232
+
233
+ @classmethod
234
+ def rewrite(cls, op, x: ir.Value, axes1: ir.Value, axes2: ir.Value):
235
+ v1 = ir_utils.get_singleton_value(axes1)
236
+ v2 = ir_utils.get_singleton_value(axes2)
237
+ axes = [v1, v2] if v1 < v2 else [v2, v1 + 1]
238
+ return op.Unsqueeze(x, op.Constant(value=ir.tensor(axes, dtype=ir.DataType.INT64)))
239
+
240
+ @classmethod
241
+ def check(cls, context, x, axes1, axes2) -> bool:
242
+ del context # Unused
243
+ del x # Unused
244
+ # Currently restricted to single element positive axis
245
+ v1 = ir_utils.get_singleton_value(axes1)
246
+ v2 = ir_utils.get_singleton_value(axes2)
247
+ if v1 is None or v2 is None:
248
+ return False
249
+ if (v1 < 0) or (v2 < 0):
250
+ return False
251
+ return True
252
+
253
+
254
+ cast_cast_rule = orp.make_rewrite_rule_from_class(CastCast)
255
+ cast_identity_rule = orp.make_rewrite_rule_from_class(CastIdentity)
256
+ expand_identity_rule = orp.make_rewrite_rule_from_class(ExpandIdentity)
257
+ reshape_reshape_rule = orp.make_rewrite_rule_from_class(ReshapeReshape)
258
+ slice_split_rule = orp.make_rewrite_rule_from_class(SlicesSplit, True)
259
+ transpose_identity_rule = orp.make_rewrite_rule_from_class(TransposeIdentity)
260
+ transpose_transpose_rule = orp.make_rewrite_rule_from_class(TransposeTranspose)
261
+ unsqueeze_unsqueeze_rule = orp.make_rewrite_rule_from_class(UnsqueezeUnsqueeze)
262
+
263
+
264
+ def llama_p0_rule_set() -> orp.RewriteRuleSet:
265
+ """Returns a set of rules which should be applied
266
+ before any other one as they usually remove unnecessary computation
267
+ such as the multiplication by 1 or two consecutive transpose.
268
+
269
+ Returns:
270
+ RewriteRuleSet
271
+ """
272
+ return orp.RewriteRuleSet(
273
+ [
274
+ no_op.mul_by_1_rule,
275
+ no_op.add_0_rule,
276
+ no_op.add_0_rule,
277
+ no_op.div_by_1_rule,
278
+ cast_cast_rule,
279
+ cast_identity_rule,
280
+ expand_identity_rule,
281
+ reshape_reshape_rule,
282
+ slice_split_rule,
283
+ transpose_identity_rule,
284
+ transpose_transpose_rule,
285
+ unsqueeze_unsqueeze_rule,
286
+ ]
287
+ )
@@ -0,0 +1,56 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ from onnxscript.rewriter import pattern
4
+
5
+ # TODO: Support 1-D constant tensors
6
+ # https://github.com/microsoft/onnx-rewriter/issues/186
7
+
8
+
9
+ # Pattern to match against
10
+ def mul_by_1(op, x):
11
+ return x * 1
12
+
13
+
14
+ def add_0(op, x):
15
+ return x + 0
16
+
17
+
18
+ def sub_0(op, x):
19
+ return x - 0
20
+
21
+
22
+ def div_by_1(op, x):
23
+ return x / 1
24
+
25
+
26
+ def dropout_zero(op, x):
27
+ return op.Dropout(x, ratio=0.0)
28
+
29
+
30
+ def dropout_inference(op, x):
31
+ return op.Dropout(x, training_mode=False)
32
+
33
+
34
+ # Replacement
35
+ def identity(op, x, **_):
36
+ return op.Identity(x)
37
+
38
+
39
+ mul_by_1_rule = pattern.RewriteRule(mul_by_1, identity)
40
+ add_0_rule = pattern.RewriteRule(add_0, identity)
41
+ sub_0_rule = pattern.RewriteRule(sub_0, identity)
42
+ div_by_1_rule = pattern.RewriteRule(div_by_1, identity)
43
+ dropout_zero_rule = pattern.RewriteRule(dropout_zero, identity)
44
+ dropout_inference_rule = pattern.RewriteRule(dropout_inference, identity)
45
+ # TODO: Include Mul by 0, 0 by Mul, 0 by Div? Those would be 0s, but not no-ops
46
+
47
+ rules = pattern.RewriteRuleSet(
48
+ [
49
+ *mul_by_1_rule.commute(),
50
+ *add_0_rule.commute(),
51
+ sub_0_rule,
52
+ div_by_1_rule,
53
+ dropout_zero_rule,
54
+ dropout_inference_rule,
55
+ ]
56
+ )
@@ -0,0 +1,50 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ from __future__ import annotations
4
+
5
+ import onnx
6
+
7
+ from onnxscript.rewriter import function_rule, pattern
8
+ from onnxscript.rewriter import rewrite as _rewrite
9
+ from onnxscript.rewriter.onnxruntime import (
10
+ fused_matmul_rule_sets,
11
+ group_normalization_merge_silu,
12
+ instance_to_group_normalization,
13
+ softmax,
14
+ transformers,
15
+ )
16
+
17
+ ORT_FUNCTION_REWRITE_RULES = [*transformers.TRANSFORMERS_FUNCTION_REWRITE_RULES]
18
+
19
+ ORT_PATTERN_REWRITE_RULES = [
20
+ *softmax.rules.rules,
21
+ *instance_to_group_normalization.rules.rules,
22
+ # NOTE: group normalization merge silu should be applied after instance to group normalization
23
+ *group_normalization_merge_silu.rules.rules,
24
+ *fused_matmul_rule_sets.fused_matmul_rule_sets(),
25
+ ]
26
+
27
+
28
+ def rewrite(
29
+ model_proto: onnx.ModelProto,
30
+ /,
31
+ function_rules: list[type[function_rule.FunctionRewriteRule]] | None = None,
32
+ pattern_rules: list[pattern.RewriteRule] | None = None,
33
+ ) -> onnx.ModelProto:
34
+ """Rewrite the model using the given rules.
35
+
36
+ Args:
37
+ model_proto: The model to rewrite.
38
+ function_rules: The function rewrite rules to apply. If None, the default rules
39
+ for onnxruntime are used.
40
+ pattern_rules: The pattern rewrite rules to apply. If None, the default rules
41
+ for onnxruntime are used.
42
+
43
+ Returns:
44
+ The rewritten model.
45
+ """
46
+ function_rules = function_rules or ORT_FUNCTION_REWRITE_RULES
47
+ pattern_rules = pattern_rules or ORT_PATTERN_REWRITE_RULES
48
+ return _rewrite(
49
+ model_proto, function_rewrite_rules=function_rules, pattern_rewrite_rules=pattern_rules
50
+ )
@@ -0,0 +1,99 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ import logging
4
+
5
+ from onnxscript import ir
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ def _convert_inputs_from_bfloat16_to_float16(value: ir.Value) -> None:
11
+ if value.dtype != ir.DataType.BFLOAT16:
12
+ return
13
+ value.dtype = ir.DataType.FLOAT16
14
+ _insert_cast_nodes_for_float16_to_bfloat16_to_inputs(value)
15
+
16
+
17
+ def _convert_outputs_from_bfloat16_to_float16(value: ir.Value) -> None:
18
+ if value.dtype != ir.DataType.BFLOAT16:
19
+ return
20
+ _insert_cast_nodes_for_bfloat16_to_float16_to_outputs(value)
21
+
22
+
23
+ def _insert_cast_nodes_for_float16_to_bfloat16_to_inputs(value: ir.Value) -> None:
24
+ user_nodes_and_indices = tuple(value.uses())
25
+
26
+ attr = ir.AttrInt64(name="to", value=ir.DataType.BFLOAT16)
27
+ cast = ir.Node(
28
+ domain="",
29
+ op_type="Cast",
30
+ inputs=[value],
31
+ num_outputs=1,
32
+ attributes=[attr],
33
+ )
34
+ cast.outputs[0].dtype = ir.DataType.BFLOAT16
35
+ cast.outputs[0].shape = value.shape
36
+
37
+ for node, index in tuple(value.uses()):
38
+ if node is cast:
39
+ continue
40
+ node.replace_input_with(index, cast.outputs[0])
41
+
42
+ # NOTE: A safer way to insert the cast node is to prepend it to the first node
43
+ # of the graph
44
+ assert user_nodes_and_indices[0][0].graph is not None, "The node should belong to a graph"
45
+ user_nodes_and_indices[0][0].graph[0].prepend(cast)
46
+
47
+
48
+ def _insert_cast_nodes_for_bfloat16_to_float16_to_outputs(value: ir.Value) -> None:
49
+ node = value.producer()
50
+ index = value.index()
51
+ if node is None or index is None:
52
+ logger.warning("Output value %s has no producer or index", value)
53
+ return
54
+
55
+ attr = ir.AttrInt64(name="to", value=ir.DataType.FLOAT16)
56
+ cast = ir.Node(
57
+ domain="",
58
+ op_type="Cast",
59
+ inputs=[node.outputs[index]],
60
+ num_outputs=1,
61
+ attributes=[attr],
62
+ )
63
+ cast.outputs[0].dtype = ir.DataType.FLOAT16
64
+ cast.outputs[0].shape = node.outputs[index].shape
65
+ node.append(cast)
66
+
67
+ assert node.graph is not None, "Node graph should not be None"
68
+ # Update graph/function outputs
69
+ for idx, graph_or_function_output in enumerate(node.graph.outputs):
70
+ if graph_or_function_output == node.outputs[index]:
71
+ node.graph.outputs[idx] = cast.outputs[0]
72
+ # Swap the output name of the node with the output name of the cast node to
73
+ # preserve the output name in the graph
74
+ node.outputs[index].name, cast.outputs[0].name = (
75
+ cast.outputs[0].name,
76
+ node.outputs[index].name,
77
+ )
78
+
79
+
80
+ def dtype_adapter_for_bfloat16_model(model: ir.Model) -> None:
81
+ """Adapt the model datatype if it's bfloat16.
82
+
83
+ Because onnxruntime does not support bfloat16 as input/output datatype, we need to
84
+ convert the bfloat16 datatype to float16. This function will convert the bfloat16
85
+ datatype to float16 and insert Cast nodes to convert float16 to bfloat16.
86
+
87
+ Model:
88
+ inputs(float16) -> Cast(bfloat16) -> nodes(bfloat16) -> Cast(float16) -> outputs(float16)
89
+
90
+ TODO: Delete this function after onnxruntime supports bfloat16.
91
+
92
+ Args:
93
+ model: The model to adapt.
94
+
95
+ """
96
+ for input in model.graph.inputs:
97
+ _convert_inputs_from_bfloat16_to_float16(input)
98
+ for output in model.graph.outputs:
99
+ _convert_outputs_from_bfloat16_to_float16(output)
@@ -0,0 +1,177 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ from __future__ import annotations
4
+
5
+ from typing import ClassVar
6
+
7
+ import onnxscript.rewriter.pattern as orp
8
+
9
+
10
+ class FusedMatMulDiv1(orp.RewriteRuleAsClass):
11
+ """Replaces ``MatMul + Div`` by FusedMatMul."""
12
+
13
+ @classmethod
14
+ def pattern(cls, op, x, y, cst):
15
+ return op.Div(op.MatMul(x, y), cst)
16
+
17
+ @classmethod
18
+ def check(cls, context, x, y, cst) -> bool:
19
+ if cst.const_value is None:
20
+ return False
21
+ value = cst.const_value.numpy()
22
+ if value.size > 1:
23
+ return False
24
+ return True
25
+
26
+ @classmethod
27
+ def rewrite(cls, op, x, y, cst):
28
+ value = cst.const_value.numpy()
29
+ c = float(value[0] if value.shape == (1,) else value)
30
+ return op.FusedMatMul(x, y, alpha=1 / c, _domain="com.microsoft")
31
+
32
+
33
+ class FusedMatMulDiv2(orp.RewriteRuleAsClass):
34
+ """Replaces ``FusedMatMul + Div`` by FusedMatMul."""
35
+
36
+ @classmethod
37
+ def pattern(cls, op, x, y, cst):
38
+ return op.Div(op.FusedMatMul(x, y, _domain="com.microsoft"), cst)
39
+
40
+ @classmethod
41
+ def check(cls, context, x, y, cst) -> bool:
42
+ if cst.const_value is None:
43
+ return False
44
+ if cst.const_value.numpy().size > 1:
45
+ return False
46
+ return True
47
+
48
+ @classmethod
49
+ def rewrite(cls, op, x, y, cst):
50
+ value = cst.const_value.numpy()
51
+ c = float(value[0] if value.shape == (1,) else value)
52
+ node = list(x.uses())[0][0] # noqa: RUF015
53
+
54
+ kwargs = {}
55
+ alpha = node.attributes.get("alpha", None)
56
+ kwargs["alpha"] = alpha.value / c if alpha else 1.0 / c
57
+ for name in ["transA", "transB", "transBatchA", "transBatchB"]:
58
+ att = node.attributes.get(name)
59
+ if att:
60
+ kwargs[name] = att.value
61
+ return op.FusedMatMul(x, y, **kwargs, _domain="com.microsoft")
62
+
63
+
64
+ class _TransposeMatMulBase(orp.RewriteRuleAsClass):
65
+ _pos: ClassVar = 1
66
+
67
+ @classmethod
68
+ def check(cls, context, x, y) -> bool:
69
+ perm = list((x if cls._pos == 1 else y).uses())[0][0].attributes["perm"].value # noqa: RUF015
70
+ expected_perm = list(range(len(perm)))
71
+ expected_perm[-2], expected_perm[-1] = expected_perm[-1], expected_perm[-2]
72
+ return perm == expected_perm
73
+
74
+ @classmethod
75
+ def rewrite(cls, op, x, y):
76
+ node = list((x if cls._pos == 2 else y).uses())[0][0] # noqa: RUF015
77
+ kwargs = {}
78
+ for name in ["alpha", "transA", "transB", "transBatchA", "transBatchB"]:
79
+ att = node.attributes.get(name)
80
+ if att:
81
+ kwargs[name] = att.value
82
+ name = "transA" if cls._pos == 1 else "transB"
83
+ kwargs[name] = 1 - kwargs.get(name, 0)
84
+ return op.FusedMatMul(x, y, **kwargs, _domain="com.microsoft")
85
+
86
+
87
+ class TransposeMatMul1(_TransposeMatMulBase):
88
+ """Replaces ``Transpose + (Fused)MatMul`` by FusedMatMul."""
89
+
90
+ @classmethod
91
+ def pattern(cls, op, x, y):
92
+ return op.MatMul(op.Transpose(x), y)
93
+
94
+
95
+ class TransposeFusedMatMul1(TransposeMatMul1):
96
+ """Replaces ``Transpose + (Fused)MatMul`` by FusedMatMul."""
97
+
98
+ @classmethod
99
+ def pattern(cls, op, x, y):
100
+ return op.FusedMatMul(op.Transpose(x), y, _domain="com.microsoft")
101
+
102
+
103
+ class TransposeMatMul2(_TransposeMatMulBase):
104
+ """Replaces ``Transpose + (Fused)MatMul`` by FusedMatMul."""
105
+
106
+ _pos: ClassVar = 2
107
+
108
+ @classmethod
109
+ def pattern(cls, op, x, y):
110
+ return op.MatMul(x, op.Transpose(y))
111
+
112
+
113
+ class TransposeFusedMatMul2(TransposeMatMul2):
114
+ """Replaces ``Transpose + (Fused)MatMul`` by FusedMatMul."""
115
+
116
+ @classmethod
117
+ def pattern(cls, op, x, y):
118
+ return op.FusedMatMul(x, op.Transpose(y), _domain="com.microsoft")
119
+
120
+
121
+ class MatMulTranspose(orp.RewriteRuleAsClass):
122
+ """Replaces ``MatMul + Transpose`` by FusedMatMul."""
123
+
124
+ @classmethod
125
+ def pattern(cls, op, x, y):
126
+ return op.Transpose(op.MatMul(x, y))
127
+
128
+ @classmethod
129
+ def check(cls, context, x, y) -> bool:
130
+ matmul = list(x.uses())[0][0] # noqa: RUF015
131
+ transpose = list(matmul.outputs[0].uses())[0][0] # noqa: RUF015
132
+ perm = transpose.attributes["perm"].value
133
+ expected_perm = list(range(len(perm)))
134
+ expected_perm[-2], expected_perm[-1] = expected_perm[-1], expected_perm[-2]
135
+ return perm == expected_perm
136
+
137
+ @classmethod
138
+ def rewrite(cls, op, x, y):
139
+ node = list(x.uses())[0][0] # noqa: RUF015
140
+ kwargs = {}
141
+ for name in ["alpha", "transA", "transB", "transBatchA", "transBatchB"]:
142
+ att = node.attributes.get(name)
143
+ if att:
144
+ kwargs[name] = att.value
145
+ for name in ["transA", "transB"]:
146
+ kwargs[name] = 1 - kwargs.get(name, 0)
147
+ return op.FusedMatMul(y, x, **kwargs, _domain="com.microsoft")
148
+
149
+
150
+ class FusedMatMulTranspose(MatMulTranspose):
151
+ """Replaces ``MatMul + Transpose`` by FusedMatMul."""
152
+
153
+ @classmethod
154
+ def pattern(cls, op, x, y):
155
+ return op.Transpose(op.FusedMatMul(x, y, _domain="com.microsoft"))
156
+
157
+
158
+ def fused_matmul_rule_sets() -> orp.RewriteRuleSet:
159
+ """Returns a set of rules introducting onnxruntime contrib obs.
160
+ This requires onnxruntime to run the model after
161
+ it is rewritten.
162
+
163
+ Returns:
164
+ RewriteRuleSet
165
+ """
166
+ return orp.RewriteRuleSet(
167
+ [
168
+ orp.make_rewrite_rule_from_class(FusedMatMulDiv1, True),
169
+ orp.make_rewrite_rule_from_class(FusedMatMulDiv2, True),
170
+ orp.make_rewrite_rule_from_class(FusedMatMulTranspose, True),
171
+ orp.make_rewrite_rule_from_class(MatMulTranspose, True),
172
+ orp.make_rewrite_rule_from_class(TransposeMatMul1, True),
173
+ orp.make_rewrite_rule_from_class(TransposeFusedMatMul1, True),
174
+ orp.make_rewrite_rule_from_class(TransposeMatMul2, True),
175
+ orp.make_rewrite_rule_from_class(TransposeFusedMatMul2, True),
176
+ ]
177
+ )