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.
- onnxscript/__init__.py +131 -0
- onnxscript/_framework_apis/__init__.py +3 -0
- onnxscript/_framework_apis/torch_2_5.py +117 -0
- onnxscript/_framework_apis/torch_2_6.py +45 -0
- onnxscript/_internal/__init__.py +0 -0
- onnxscript/_internal/analysis.py +229 -0
- onnxscript/_internal/ast_utils.py +64 -0
- onnxscript/_internal/autocast.py +250 -0
- onnxscript/_internal/deprecation.py +78 -0
- onnxscript/_internal/param_manipulation.py +148 -0
- onnxscript/_internal/runtime_typing.py +43 -0
- onnxscript/_internal/utils.py +99 -0
- onnxscript/_internal/version_utils.py +118 -0
- onnxscript/_legacy_ir/__init__.py +341 -0
- onnxscript/_legacy_ir/visitor.py +937 -0
- onnxscript/_thirdparty/asciichartpy.py +313 -0
- onnxscript/backend/__init__.py +2 -0
- onnxscript/backend/onnx_backend.py +303 -0
- onnxscript/backend/onnx_export.py +885 -0
- onnxscript/converter.py +1470 -0
- onnxscript/evaluator.py +619 -0
- onnxscript/function_libs/tools/torch_lib/deduce_type_constraints.py +403 -0
- onnxscript/function_libs/tools/torch_lib/generate_aten_signatures.py +333 -0
- onnxscript/function_libs/tools/torch_lib/generate_prims_signatures.py +331 -0
- onnxscript/function_libs/torch_lib/__init__.py +12 -0
- onnxscript/function_libs/torch_lib/_constants.py +5 -0
- onnxscript/function_libs/torch_lib/_flags.py +58 -0
- onnxscript/function_libs/torch_lib/graph_building/__init__.py +56 -0
- onnxscript/function_libs/torch_lib/graph_building/_graph_building_ir.py +723 -0
- onnxscript/function_libs/torch_lib/graph_building/_graph_building_torch.py +1125 -0
- onnxscript/function_libs/torch_lib/ops/__init__.py +27 -0
- onnxscript/function_libs/torch_lib/ops/common.py +80 -0
- onnxscript/function_libs/torch_lib/ops/core.py +8935 -0
- onnxscript/function_libs/torch_lib/ops/fft.py +385 -0
- onnxscript/function_libs/torch_lib/ops/linalg.py +399 -0
- onnxscript/function_libs/torch_lib/ops/nested.py +25 -0
- onnxscript/function_libs/torch_lib/ops/nn.py +2713 -0
- onnxscript/function_libs/torch_lib/ops/prims.py +850 -0
- onnxscript/function_libs/torch_lib/ops/quantized_decomposed.py +63 -0
- onnxscript/function_libs/torch_lib/ops/sparse.py +23 -0
- onnxscript/function_libs/torch_lib/ops/special.py +387 -0
- onnxscript/function_libs/torch_lib/ops/vision.py +25 -0
- onnxscript/function_libs/torch_lib/registration.py +151 -0
- onnxscript/function_libs/torch_lib/tensor_typing.py +74 -0
- onnxscript/ir/__init__.py +153 -0
- onnxscript/ir/_convenience.py +447 -0
- onnxscript/ir/_core.py +3119 -0
- onnxscript/ir/_display.py +49 -0
- onnxscript/ir/_enums.py +163 -0
- onnxscript/ir/_graph_comparison.py +23 -0
- onnxscript/ir/_io.py +97 -0
- onnxscript/ir/_linked_list.py +276 -0
- onnxscript/ir/_metadata.py +44 -0
- onnxscript/ir/_name_authority.py +72 -0
- onnxscript/ir/_polyfill.py +25 -0
- onnxscript/ir/_protocols.py +598 -0
- onnxscript/ir/_schemas.py +548 -0
- onnxscript/ir/_tape.py +120 -0
- onnxscript/ir/_type_casting.py +106 -0
- onnxscript/ir/convenience.py +32 -0
- onnxscript/ir/external_data.py +396 -0
- onnxscript/ir/passes/__init__.py +33 -0
- onnxscript/ir/passes/_pass_infra.py +172 -0
- onnxscript/ir/serde.py +1620 -0
- onnxscript/ir/tensor_adapters.py +122 -0
- onnxscript/ir/traversal.py +82 -0
- onnxscript/irbuilder.py +542 -0
- onnxscript/main.py +167 -0
- onnxscript/onnx_opset/__init__.py +232 -0
- onnxscript/onnx_opset/_impl/opset1.py +4100 -0
- onnxscript/onnx_opset/_impl/opset10.py +1227 -0
- onnxscript/onnx_opset/_impl/opset11.py +4013 -0
- onnxscript/onnx_opset/_impl/opset12.py +1078 -0
- onnxscript/onnx_opset/_impl/opset13.py +3924 -0
- onnxscript/onnx_opset/_impl/opset14.py +999 -0
- onnxscript/onnx_opset/_impl/opset15.py +604 -0
- onnxscript/onnx_opset/_impl/opset16.py +1255 -0
- onnxscript/onnx_opset/_impl/opset17.py +561 -0
- onnxscript/onnx_opset/_impl/opset18.py +1803 -0
- onnxscript/onnx_opset/_impl/opset19.py +1942 -0
- onnxscript/onnx_opset/_impl/opset2.py +218 -0
- onnxscript/onnx_opset/_impl/opset20.py +675 -0
- onnxscript/onnx_opset/_impl/opset21.py +1976 -0
- onnxscript/onnx_opset/_impl/opset22.py +2588 -0
- onnxscript/onnx_opset/_impl/opset3.py +199 -0
- onnxscript/onnx_opset/_impl/opset4.py +77 -0
- onnxscript/onnx_opset/_impl/opset5.py +84 -0
- onnxscript/onnx_opset/_impl/opset6.py +944 -0
- onnxscript/onnx_opset/_impl/opset7.py +1243 -0
- onnxscript/onnx_opset/_impl/opset8.py +444 -0
- onnxscript/onnx_opset/_impl/opset9.py +1485 -0
- onnxscript/onnx_opset/_impl/opset_ai_onnx_ml1.py +974 -0
- onnxscript/onnx_opset/_impl/opset_ai_onnx_ml2.py +112 -0
- onnxscript/onnx_opset/_impl/opset_ai_onnx_ml3.py +308 -0
- onnxscript/onnx_opset/_impl/opset_ai_onnx_ml4.py +129 -0
- onnxscript/onnx_opset/_impl/opset_ai_onnx_ml5.py +158 -0
- onnxscript/onnx_opset/_impl/opset_ai_onnx_preview_training1.py +577 -0
- onnxscript/onnx_types.py +229 -0
- onnxscript/optimizer/__init__.py +39 -0
- onnxscript/optimizer/_constant_folding.py +1083 -0
- onnxscript/optimizer/_inliner.py +312 -0
- onnxscript/optimizer/_legacy/_optimizer.py +98 -0
- onnxscript/optimizer/_legacy/_remove_unused_proto.py +144 -0
- onnxscript/optimizer/_legacy/_simple_function_folding.py +243 -0
- onnxscript/optimizer/_legacy/constant_folding.py +293 -0
- onnxscript/optimizer/_legacy/evaluator.py +439 -0
- onnxscript/optimizer/_optimizer.py +61 -0
- onnxscript/optimizer/_remove_unused.py +106 -0
- onnxscript/optimizer/_remove_unused_function.py +72 -0
- onnxscript/py.typed +1 -0
- onnxscript/rewriter/__init__.py +56 -0
- onnxscript/rewriter/_ir_utils.py +111 -0
- onnxscript/rewriter/broadcast_to_matmul.py +180 -0
- onnxscript/rewriter/cast_constant_of_shape.py +50 -0
- onnxscript/rewriter/collapse_slices.py +141 -0
- onnxscript/rewriter/erfgelu.py +27 -0
- onnxscript/rewriter/function_rule.py +232 -0
- onnxscript/rewriter/gemm_to_matmul_add.py +21 -0
- onnxscript/rewriter/generic_pattern.py +700 -0
- onnxscript/rewriter/llama_rule_sets.py +287 -0
- onnxscript/rewriter/no_op.py +56 -0
- onnxscript/rewriter/onnxruntime/__init__.py +50 -0
- onnxscript/rewriter/onnxruntime/bfloat16_utils/bfloat16_converter.py +99 -0
- onnxscript/rewriter/onnxruntime/fused_matmul_rule_sets.py +177 -0
- onnxscript/rewriter/onnxruntime/group_normalization_merge_silu.py +64 -0
- onnxscript/rewriter/onnxruntime/instance_to_group_normalization.py +155 -0
- onnxscript/rewriter/onnxruntime/softmax.py +63 -0
- onnxscript/rewriter/onnxruntime/transformers/__init__.py +21 -0
- onnxscript/rewriter/onnxruntime/transformers/biassplitgelu.py +31 -0
- onnxscript/rewriter/onnxruntime/transformers/fastgelu.py +29 -0
- onnxscript/rewriter/onnxruntime/transformers/layernorm.py +47 -0
- onnxscript/rewriter/onnxruntime/transformers/multihead_attention.py +715 -0
- onnxscript/rewriter/ort_fusions/__init__.py +9 -0
- onnxscript/rewriter/ort_fusions/_core.py +28 -0
- onnxscript/rewriter/ort_fusions/_smollm_1.py +253 -0
- onnxscript/rewriter/ort_fusions/_smollm_2.py +467 -0
- onnxscript/rewriter/ort_fusions/_test_models.py +122 -0
- onnxscript/rewriter/ort_fusions/_test_utils.py +42 -0
- onnxscript/rewriter/ort_fusions/cos_sin_cache.py +154 -0
- onnxscript/rewriter/ort_fusions/gqa.py +156 -0
- onnxscript/rewriter/ort_fusions/mha.py +198 -0
- onnxscript/rewriter/ort_fusions/rms_normalization.py +95 -0
- onnxscript/rewriter/ort_fusions/rotary_embedding.py +64 -0
- onnxscript/rewriter/ort_fusions/sdpa.py +75 -0
- onnxscript/rewriter/ort_fusions/skip_normalization.py +46 -0
- onnxscript/rewriter/pattern.py +1714 -0
- onnxscript/rewriter/testing.py +77 -0
- onnxscript/sourceinfo.py +59 -0
- onnxscript/tensor.py +227 -0
- onnxscript/testing/__init__.py +482 -0
- onnxscript/tools/__init__.py +4 -0
- onnxscript/tools/benchmark/__init__.py +23 -0
- onnxscript/tools/benchmark/benchmark_helpers.py +783 -0
- onnxscript/tools/benchmark/benchmark_run.py +140 -0
- onnxscript/tools/benchmark/export_model.py +207 -0
- onnxscript/tools/benchmark/export_model_batch.py +146 -0
- onnxscript/tools/memory_peak.py +244 -0
- onnxscript/tools/training_helper.py +50 -0
- onnxscript/tools/transformers_models/__init__.py +190 -0
- onnxscript/tools/transformers_models/llama.py +168 -0
- onnxscript/tools/transformers_models/mistral.py +238 -0
- onnxscript/tools/transformers_models/phi.py +248 -0
- onnxscript/tools/transformers_models/phi3.py +259 -0
- onnxscript/type_annotation.py +281 -0
- onnxscript/utils/__init__.py +0 -0
- onnxscript/utils/evaluation_utils.py +56 -0
- onnxscript/utils/timing_utils.py +33 -0
- onnxscript/utils/utils.py +84 -0
- onnxscript/values.py +790 -0
- onnxscript/version_converter/__init__.py +21 -0
- onnxscript/version_converter/_version_converter.py +314 -0
- onnxscript-0.1.0.dist-info/LICENSE +21 -0
- onnxscript-0.1.0.dist-info/METADATA +370 -0
- onnxscript-0.1.0.dist-info/RECORD +176 -0
- onnxscript-0.1.0.dist-info/WHEEL +5 -0
- 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()
|