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,140 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ # pylint: disable=consider-using-with,import-outside-toplevel
4
+ from __future__ import annotations
5
+
6
+ import multiprocessing
7
+ import os
8
+ import platform
9
+ import re
10
+ import subprocess
11
+ import sys
12
+
13
+
14
+ class BenchmarkError(RuntimeError):
15
+ pass
16
+
17
+
18
+ def get_machine() -> dict[str, str | int | float | tuple[int, int]]:
19
+ """Returns the machine specification."""
20
+ config: dict[str, str | int | float | tuple[int, int]] = dict(
21
+ machine=str(platform.machine()),
22
+ processor=str(platform.processor()),
23
+ version=str(sys.version),
24
+ config=int(multiprocessing.cpu_count()),
25
+ executable=str(sys.executable),
26
+ )
27
+ try:
28
+ import torch.cuda
29
+ except ImportError:
30
+ return config
31
+
32
+ config["has_cuda"] = bool(torch.cuda.is_available())
33
+ if config["has_cuda"]:
34
+ config["capability"] = torch.cuda.get_device_capability(0)
35
+ config["device_name"] = str(torch.cuda.get_device_name(0))
36
+ return config
37
+
38
+
39
+ def _cmd_line(script_name: str, **kwargs: dict[str, str | int | float]) -> list[str]:
40
+ args = [sys.executable, "-m", script_name]
41
+ for k, v in kwargs.items():
42
+ args.append(f"--{k}")
43
+ args.append(str(v))
44
+ return args
45
+
46
+
47
+ def _extract_metrics(text: str) -> dict[str, str]:
48
+ reg = re.compile(r":(.*?),(.*.?);")
49
+ res = reg.findall(text)
50
+ if len(res) == 0:
51
+ return {}
52
+ return dict(res)
53
+
54
+
55
+ def _make_prefix(script_name: str, index: int) -> str:
56
+ name = os.path.splitext(script_name)[0]
57
+ return f"{name}_dort_c{index}_"
58
+
59
+
60
+ def run_benchmark(
61
+ script_name: str,
62
+ configs: list[dict[str, str | int | float]],
63
+ verbose: int = 0,
64
+ stop_if_exception: bool = True,
65
+ dort_dump: bool = False,
66
+ ) -> list[dict[str, str | int | float | tuple[int, int]]]:
67
+ """
68
+ Runs a script multiple times and extract information from the output
69
+ following the pattern ``:<metric>,<value>;``.
70
+
71
+ :param script_name: python script to run
72
+ :param configs: list of execution to do
73
+ :param stop_if_exception: stop if one experiment failed, otherwise continue
74
+ :param verbose: use tqdm to follow the progress
75
+ :param dort_dump: dump onnx file if dort is used
76
+ :return: values
77
+ """
78
+ if verbose:
79
+ try:
80
+ from tqdm import tqdm
81
+
82
+ loop = tqdm(configs)
83
+ except ImportError:
84
+ loop = configs
85
+ else:
86
+ loop = configs
87
+
88
+ data: list[dict[str, str | int | float | tuple[int, int]]] = []
89
+ for i, config in enumerate(loop):
90
+ cmd = _cmd_line(script_name, **config)
91
+
92
+ if dort_dump:
93
+ os.environ["ONNXRT_DUMP_PATH"] = _make_prefix(script_name, i)
94
+ else:
95
+ os.environ["ONNXRT_DUMP_PATH"] = ""
96
+ if verbose > 3:
97
+ print(f"[run_benchmark] cmd={cmd if isinstance(cmd, str) else ' '.join(cmd)}")
98
+
99
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
100
+ try:
101
+ res = p.communicate(timeout=30)
102
+ out, err = res
103
+ serr = err.decode("utf-8", errors="ignore")
104
+ except subprocess.TimeoutExpired as e:
105
+ p.kill()
106
+ res = p.communicate()
107
+ out, err = res
108
+ serr = f"{e}\n:timeout,1;{err.decode('utf-8', errors='ignore')}"
109
+ sout = out.decode("utf-8", errors="ignore")
110
+
111
+ if "ONNXRuntimeError" in serr or "ONNXRuntimeError" in sout:
112
+ if stop_if_exception: # pylint: disable=no-else-raise
113
+ raise RuntimeError(
114
+ f"Unable to continue with config {config} due to the "
115
+ f"following error\n{serr}"
116
+ f"\n----OUTPUT--\n{sout}"
117
+ )
118
+
119
+ metrics = _extract_metrics(sout)
120
+ if len(metrics) == 0:
121
+ if stop_if_exception: # pylint: disable=no-else-raise
122
+ raise BenchmarkError(
123
+ f"Unable (2) to continue with config {config}, no metric was "
124
+ f"collected.\n--ERROR--\n{serr}\n--OUTPUT--\n{sout}"
125
+ )
126
+ else:
127
+ metrics = {}
128
+ metrics.update(config)
129
+ metrics["ERROR"] = serr
130
+ metrics["OUTPUT"] = sout
131
+ metrics["CMD"] = f"[{' '.join(cmd)}]"
132
+ data.append(metrics) # type: ignore[arg-type]
133
+ if verbose > 5:
134
+ print("--------------- ERROR")
135
+ print(serr)
136
+ if verbose >= 10:
137
+ print("--------------- OUTPUT")
138
+ print(sout)
139
+
140
+ return data
@@ -0,0 +1,207 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+ # pylint: disable=import-outside-toplevel
4
+
5
+ import hashlib
6
+ import pprint
7
+ import textwrap
8
+ import time
9
+ from typing import Any
10
+
11
+
12
+ def main(args=None):
13
+ import onnxscript.tools.benchmark
14
+
15
+ kwargs: dict[str, Any] = onnxscript.tools.benchmark.get_parsed_args(
16
+ "export_model",
17
+ description=textwrap.dedent(
18
+ """Measures the inference time for a particular model.
19
+ This script can be used to quickly evaluate the improvment made by a pattern optimization
20
+ for a particular model.
21
+
22
+ If one value contains ",", the script understand multiple commands
23
+ must be run. It computes all the possible configurations.
24
+ In that case, it produces a csv file (if output_data is not empty) with all the results.
25
+
26
+ Example with a large phi model::
27
+
28
+ python -m onnxscript.tools.benchmark.export_model --model phi --device cuda --config large --num_hidden_layers=6 --dtype=float32 --dynamic=0 --verbose=1 --exporter=dynamo
29
+
30
+ Example with a medium llama model::
31
+
32
+ python -m onnxscript.tools.benchmark.export_model --model llama --device cuda --config medium --num_hidden_layers=1 --dtype=float32 --dynamic=0 --verbose=1 --exporter=dynamo --optimization=rewrite/optimize/inline/llama0/onnxruntime
33
+ """
34
+ ),
35
+ repeat=(10, "number of inferences to measure"),
36
+ warmup=(5, "number of inferences to warm"),
37
+ model=("phi", "model to measure, llama, mistral, phi, ..."),
38
+ exporter=("dynamo", "script, dynamo"),
39
+ device=("cpu", "'cpu' or 'cuda'"),
40
+ target_opset=(18, "opset to convert into, use with backend=custom"),
41
+ config=("small", "default, medium, or small to test"),
42
+ verbose=(0, "verbosity"),
43
+ dump_folder=("", "if not empty, dump the model in that folder"),
44
+ dump_ort=(1, "produce the model optimized by onnxruntime"),
45
+ ort_optimize=(1, "enable or disable onnxruntime optimization"),
46
+ dtype=("default", "cast the model and the inputs into this type"),
47
+ dynamic=(0, "use dynamic shapes"),
48
+ num_hidden_layers=(1, "number of hidden layers"),
49
+ with_mask=(1, "with or without mask, dynamo may fail with a mask"),
50
+ optimization=(
51
+ "",
52
+ "optimization scenario, comma separated value, optimize, rewrite, "
53
+ "inline, set of patterns (default, onnxruntime, customops)",
54
+ ),
55
+ implementation=("eager", "eager or sdpa"),
56
+ memory_peak=(0, "measure the memory peak during conversion"),
57
+ output_data=(
58
+ "export_model.csv",
59
+ "produces a csv file with the data if multiple configurations are tested",
60
+ ),
61
+ new_args=args,
62
+ )
63
+ if onnxscript.tools.benchmark.multi_run(kwargs):
64
+ import onnxscript.tools.benchmark.benchmark_run
65
+
66
+ configs = onnxscript.tools.benchmark.make_configs(kwargs)
67
+ data = onnxscript.tools.benchmark.benchmark_run.run_benchmark(
68
+ "onnxscript.tools.benchmark.export_model",
69
+ configs,
70
+ kwargs["verbose"],
71
+ stop_if_exception=False,
72
+ )
73
+ if kwargs["verbose"] > 2:
74
+ pprint.pprint(data if kwargs["verbose"] > 3 else data[:2])
75
+ if kwargs["output_data"]:
76
+ df = onnxscript.tools.benchmark.make_dataframe_from_benchmark_data(data)
77
+ df.to_csv(kwargs["output_data"], index=False)
78
+ df.to_excel(kwargs["output_data"] + ".xlsx", index=False)
79
+ if kwargs["verbose"]:
80
+ print(df)
81
+ else:
82
+ print("-------------------")
83
+ print("[export_model]")
84
+ pprint.pprint(kwargs)
85
+ print("-------------------")
86
+
87
+ # Import is delayed so that help is being display faster (without having to import heavy packages).
88
+ import onnxscript.tools
89
+ import onnxscript.tools.memory_peak
90
+ import onnxscript.tools.transformers_models
91
+
92
+ print(
93
+ f"[export_model] create the model and inputs for {kwargs['model']!r} and config {kwargs['config']!r}"
94
+ )
95
+ begin = time.perf_counter()
96
+ model, example_inputs, dynamic_shapes = (
97
+ onnxscript.tools.transformers_models.get_model_and_inputs(
98
+ warmup=kwargs["warmup"],
99
+ repeat=kwargs["repeat"],
100
+ model=kwargs["model"],
101
+ config=kwargs["config"],
102
+ dynamic_shapes=kwargs["dynamic"],
103
+ device=kwargs["device"],
104
+ num_hidden_layers=kwargs["num_hidden_layers"],
105
+ with_mask=kwargs["with_mask"],
106
+ implementation=kwargs["implementation"],
107
+ dtype=kwargs["dtype"],
108
+ )
109
+ )
110
+ print(f"[export_model] model created in {time.perf_counter() - begin}")
111
+ if kwargs["dynamic"]:
112
+ print(f"[export_model] dynamic_shapes={dynamic_shapes}")
113
+ msg = [tuple(i.shape for i in inp) for inp in example_inputs]
114
+ print(f"[export_model] input_shapes={msg}")
115
+ conversion: dict[str, Any] = {}
116
+ memory_stats: dict[str, float] = {}
117
+
118
+ if kwargs["exporter"] == "eager":
119
+ print("[export_model] start benchmark")
120
+ begin = time.perf_counter()
121
+ result = onnxscript.tools.benchmark.run_inference(
122
+ model,
123
+ example_inputs,
124
+ warmup=kwargs["warmup"],
125
+ repeat=kwargs["repeat"],
126
+ verbose=kwargs["verbose"],
127
+ )
128
+ print(f"[export_model] benchmark done in {time.perf_counter() - begin}")
129
+ else:
130
+ print(
131
+ f"[export_model] export to onnx with exporter={kwargs['exporter']!r} "
132
+ f"and optimization={kwargs['optimization']!r}"
133
+ )
134
+ begin = time.perf_counter()
135
+ if kwargs["optimization"]:
136
+ m = hashlib.sha256()
137
+ m.update(kwargs["optimization"].encode())
138
+ so = m.hexdigest()[:5]
139
+ else:
140
+ so = ""
141
+ name = "_".join(
142
+ [
143
+ kwargs["model"],
144
+ kwargs["exporter"],
145
+ "dynamic" if kwargs["dynamic"] else "static",
146
+ kwargs["dtype"].replace("float", "fp"),
147
+ kwargs["device"],
148
+ kwargs["config"],
149
+ f"h{kwargs['num_hidden_layers']}",
150
+ so,
151
+ ],
152
+ )
153
+ filename = f"em_{name}.onnx"
154
+
155
+ memory_session = (
156
+ onnxscript.tools.memory_peak.start_spying_on(cuda=kwargs["device"] == "cuda")
157
+ if kwargs["memory_peak"]
158
+ else None
159
+ )
160
+ print(f"[export_model] start memory peak monitoring {memory_session}")
161
+ proto = onnxscript.tools.benchmark.common_export(
162
+ model=model,
163
+ inputs=example_inputs[0],
164
+ exporter=kwargs["exporter"],
165
+ target_opset=kwargs["target_opset"],
166
+ folder=kwargs["dump_folder"],
167
+ filename=filename,
168
+ dynamic_shapes=dynamic_shapes if kwargs["dynamic"] else None,
169
+ optimization=kwargs["optimization"],
170
+ verbose=kwargs["verbose"],
171
+ stats=conversion,
172
+ )
173
+ print(f"[export_model] export to onnx done in {time.perf_counter() - begin}")
174
+ if memory_session is not None:
175
+ memory_results = memory_session.stop()
176
+ print(f"[export_model] ends memory monitoring {memory_results}")
177
+ memory_stats = onnxscript.tools.memory_peak.flatten(
178
+ memory_results, prefix="memory_"
179
+ )
180
+ else:
181
+ memory_stats = {}
182
+
183
+ result = onnxscript.tools.benchmark.run_onnx_inference(
184
+ proto,
185
+ example_inputs,
186
+ warmup=kwargs["warmup"],
187
+ repeat=kwargs["repeat"],
188
+ verbose=kwargs["verbose"],
189
+ ort_optimize=kwargs["ort_optimize"],
190
+ torch_model=model,
191
+ )
192
+
193
+ print("[export_model] end")
194
+ print("------------------------------")
195
+ for k, v in sorted(kwargs.items()):
196
+ print(f":{k},{v};")
197
+ for k, v in sorted(conversion.items()):
198
+ print(f":{k},{v};")
199
+ if memory_stats:
200
+ for k, v in memory_stats.items():
201
+ print(f":{k},{v};")
202
+ for k, v in sorted(result.items()):
203
+ print(f":{k},{v};")
204
+
205
+
206
+ if __name__ == "__main__":
207
+ main()
@@ -0,0 +1,146 @@
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+ # pylint: disable=import-outside-toplevel
4
+
5
+ from __future__ import annotations
6
+
7
+ import pprint
8
+ import textwrap
9
+ from typing import Any
10
+
11
+ import onnxscript.tools.benchmark
12
+
13
+
14
+ def main(args: list[str] | None = None):
15
+ kwargs: dict[str, Any] = onnxscript.tools.benchmark.get_parsed_args(
16
+ "export_model",
17
+ description=textwrap.dedent(
18
+ """Measures the inference time for a particular model.
19
+ It runs export_model to compare several optimization settings.
20
+
21
+ Example::
22
+
23
+ python -m onnxscript.tools.benchmark.export_model_batch --model phi --device cuda --config medium --num_hidden_layers=1 --dtype=float32 --dynamic=0 --verbose=1
24
+ """
25
+ ),
26
+ repeat=(10, "number of inferences to measure"),
27
+ warmup=(5, "number of inferences to warm"),
28
+ model=("phi", "model to measure, llama, mistral, phi, ..."),
29
+ device=("cpu", "'cpu' or 'cuda'"),
30
+ target_opset=(18, "opset to convert into, use with backend=custom"),
31
+ config=("small", "default, medium, or small to test"),
32
+ verbose=(0, "verbosity"),
33
+ dtype=("default", "cast the model and the inputs into this type"),
34
+ dynamic=(0, "use dynamic shapes"),
35
+ num_hidden_layers=(1, "number of hidden layers"),
36
+ with_mask=(1, "with or without mask, dynamo may fail with a mask"),
37
+ implementation=("eager", "eager or sdpa"),
38
+ new_args=args,
39
+ )
40
+
41
+ print("-------------------")
42
+ print("[export_model]")
43
+ pprint.pprint(kwargs)
44
+ print("-------------------")
45
+
46
+ import pandas
47
+
48
+ try:
49
+ import openpyxl
50
+ except ImportError:
51
+ openpyxl = None
52
+
53
+ from onnxscript.tools.benchmark.benchmark_helpers import (
54
+ BenchmarkError,
55
+ run_benchmark,
56
+ )
57
+
58
+ script_name = "onnxscript.tools.benchmark.export_model"
59
+
60
+ configs: list[dict[str, Any]] = [
61
+ dict(exporter="eager"),
62
+ dict(ort_optimize=1, exporter="script"),
63
+ dict(ort_optimize=1, optimization="optimize/rewrite/inline", exporter="script"),
64
+ dict(ort_optimize=0, optimization="optimize/rewrite/inline", exporter="script"),
65
+ dict(ort_optimize=1, optimization="", exporter="dynamo"),
66
+ dict(ort_optimize=1, optimization="optimize/rewrite/inline", exporter="dynamo"),
67
+ dict(ort_optimize=0, optimization="optimize/rewrite/inline", exporter="dynamo"),
68
+ ]
69
+ common_kwargs: dict[str, Any] = kwargs.copy()
70
+ common_kwargs["verbose"] = max(common_kwargs["verbose"] - 1, 0)
71
+ for c in configs:
72
+ c.update(common_kwargs)
73
+
74
+ if kwargs["verbose"]:
75
+ for i, cf in enumerate(configs):
76
+ print(f"[export_common_batch] config {i + 1}: {cf}")
77
+
78
+ ################################
79
+ # Running configuration.
80
+
81
+ try:
82
+ data = run_benchmark(
83
+ script_name,
84
+ configs,
85
+ verbose=kwargs["verbose"],
86
+ stop_if_exception=False,
87
+ )
88
+ data_collected = True
89
+ except BenchmarkError as e:
90
+ if kwargs["verbose"]:
91
+ print(e)
92
+ data_collected = False
93
+
94
+ prefix = "_".join(
95
+ [
96
+ "emb_",
97
+ kwargs["model"],
98
+ "dynamic" if kwargs["dynamic"] else "static",
99
+ kwargs["dtype"].replace("float", "fp"),
100
+ kwargs["device"],
101
+ kwargs["config"],
102
+ f"h{kwargs['num_hidden_layers']}",
103
+ ],
104
+ )
105
+
106
+ if data_collected:
107
+ df = pandas.DataFrame(data)
108
+ df = df.drop(["OUTPUT", "ERROR"], axis=1)
109
+ df["repeat_time"] = df["repeat_time"].astype(float)
110
+ df_eager = df[(df["implementation"] == "eager") & (df["exporter"] == "eager")][
111
+ "repeat_time"
112
+ ].dropna()
113
+ if df_eager.shape[0] > 0:
114
+ min_eager = df_eager.min()
115
+ df["increase"] = df["repeat_time"] / min_eager - 1
116
+ filename = f"{prefix}_with_cmd.csv"
117
+ df.to_csv(filename, index=False)
118
+
119
+ df = df.drop(["CMD"], axis=1)
120
+ filename = f"{prefix}.csv"
121
+ df.to_csv(filename, index=False)
122
+ df = pandas.read_csv(filename) # to cast type
123
+ print(df)
124
+
125
+ # summary
126
+ cs = [
127
+ c
128
+ for c in ["exporter", "optimization", "warmup_time", "repeat_time", "increase"]
129
+ if c in df.columns
130
+ ]
131
+ dfs = df[cs]
132
+ if openpyxl:
133
+ filename = f"{prefix}_summary.xlsx"
134
+ dfs.to_excel(filename, index=False)
135
+ filename = f"{prefix}_summary.csv"
136
+ dfs.to_csv(filename, index=False)
137
+ print(dfs)
138
+
139
+ ########################
140
+ # First lines.
141
+
142
+ print(df.head(2).T)
143
+
144
+
145
+ if __name__ == "__main__":
146
+ main()