onnx-diagnostic 0.8.7__py3-none-any.whl → 0.8.8__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.
- onnx_diagnostic/__init__.py +1 -1
- onnx_diagnostic/ci_models/export_phi4_mm.py +1 -1
- onnx_diagnostic/export/api.py +294 -5
- onnx_diagnostic/export/dynamic_shapes.py +45 -3
- onnx_diagnostic/export/shape_helper.py +1 -0
- onnx_diagnostic/helpers/cache_helper.py +0 -8
- onnx_diagnostic/helpers/fake_tensor_helper.py +26 -5
- onnx_diagnostic/helpers/helper.py +30 -1
- onnx_diagnostic/helpers/ort_session.py +5 -0
- onnx_diagnostic/tasks/image_text_to_text.py +4 -4
- onnx_diagnostic/torch_export_patches/patch_details.py +3 -3
- onnx_diagnostic/torch_export_patches/patches/_patch_transformers_dynamic_cache.py +14 -5
- onnx_diagnostic/torch_export_patches/patches/_patch_transformers_rotary_embedding.py +2 -2
- onnx_diagnostic/torch_models/validate.py +48 -0
- {onnx_diagnostic-0.8.7.dist-info → onnx_diagnostic-0.8.8.dist-info}/METADATA +3 -1
- {onnx_diagnostic-0.8.7.dist-info → onnx_diagnostic-0.8.8.dist-info}/RECORD +19 -19
- {onnx_diagnostic-0.8.7.dist-info → onnx_diagnostic-0.8.8.dist-info}/WHEEL +0 -0
- {onnx_diagnostic-0.8.7.dist-info → onnx_diagnostic-0.8.8.dist-info}/licenses/LICENSE.txt +0 -0
- {onnx_diagnostic-0.8.7.dist-info → onnx_diagnostic-0.8.8.dist-info}/top_level.txt +0 -0
onnx_diagnostic/__init__.py
CHANGED
|
@@ -973,7 +973,7 @@ def main(
|
|
|
973
973
|
kwargs=export_inputs,
|
|
974
974
|
dynamic_shapes=use_dyn_not_str(dynamic_shapes),
|
|
975
975
|
)
|
|
976
|
-
patches = details.
|
|
976
|
+
patches = details.patches_involved_in_graph(ep.graph)
|
|
977
977
|
report = details.make_report(patches, format="rst")
|
|
978
978
|
with open(f"{basename}.patches_details.rst", "w") as f:
|
|
979
979
|
f.write(report)
|
onnx_diagnostic/export/api.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import inspect
|
|
2
|
+
import os
|
|
3
|
+
import textwrap
|
|
4
|
+
from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Union
|
|
2
5
|
import torch
|
|
6
|
+
from .dynamic_shapes import ModelInputs
|
|
3
7
|
from .onnx_plug import EagerDirectReplacementWithOnnx
|
|
8
|
+
from ..helpers import string_type
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
def get_main_dispatcher(
|
|
@@ -70,6 +75,7 @@ def to_onnx(
|
|
|
70
75
|
inline: bool = True,
|
|
71
76
|
) -> Any:
|
|
72
77
|
"""
|
|
78
|
+
Exports one model into ONNX.
|
|
73
79
|
Common API for exporters. By default, the models are optimized to use the
|
|
74
80
|
most efficient kernels implemented in :epkg:`onnxruntime`.
|
|
75
81
|
|
|
@@ -126,8 +132,12 @@ def to_onnx(
|
|
|
126
132
|
from experimental_experiment.xbuilder import OptimizationOptions
|
|
127
133
|
|
|
128
134
|
options = None
|
|
135
|
+
export_options = None
|
|
129
136
|
if exporter_kwargs is not None:
|
|
130
137
|
options = exporter_kwargs.pop("options", None)
|
|
138
|
+
export_options = exporter_kwargs.pop("export_options", None)
|
|
139
|
+
if export_options is None:
|
|
140
|
+
export_options = ExportOptions(save_ep=save_ep)
|
|
131
141
|
if options is None and optimize:
|
|
132
142
|
options = OptimizationOptions(
|
|
133
143
|
patterns="default+onnxruntime" if optimizer_for_ort else "default"
|
|
@@ -138,7 +148,7 @@ def to_onnx(
|
|
|
138
148
|
else None
|
|
139
149
|
)
|
|
140
150
|
|
|
141
|
-
|
|
151
|
+
proto, opt_stats = _to_onnx(
|
|
142
152
|
mod,
|
|
143
153
|
args=args,
|
|
144
154
|
kwargs=kwargs,
|
|
@@ -150,16 +160,52 @@ def to_onnx(
|
|
|
150
160
|
dynamic_shapes=dynamic_shapes,
|
|
151
161
|
large_model=True,
|
|
152
162
|
output_dynamic_shapes=output_dynamic_shapes,
|
|
153
|
-
export_options=
|
|
163
|
+
export_options=export_options,
|
|
154
164
|
options=options,
|
|
155
165
|
inline=inline,
|
|
156
166
|
dispatcher=main_dispatcher,
|
|
157
167
|
optimize=optimize,
|
|
168
|
+
return_optimize_report=True,
|
|
158
169
|
**(exporter_kwargs or {}),
|
|
159
170
|
)
|
|
171
|
+
if opt_stats and filename and os.path.exists(filename):
|
|
172
|
+
import pandas
|
|
173
|
+
|
|
174
|
+
stat_filename = f"{os.path.splitext(filename)[0]}.opt.xlsx"
|
|
175
|
+
pattern_stats = []
|
|
176
|
+
for k, v in opt_stats.items():
|
|
177
|
+
if "time" in k:
|
|
178
|
+
pattern_stats.append(dict(level="main", pattern=k, time_in=v))
|
|
179
|
+
pattern_stats.extend(
|
|
180
|
+
[{**obs, "level": "detailed"} for obs in opt_stats["optimization"]]
|
|
181
|
+
)
|
|
182
|
+
df = pandas.DataFrame(pattern_stats)
|
|
183
|
+
df.to_excel(stat_filename, index=False)
|
|
184
|
+
cols = [
|
|
185
|
+
c
|
|
186
|
+
for c in [
|
|
187
|
+
"level",
|
|
188
|
+
"pattern",
|
|
189
|
+
"time_in",
|
|
190
|
+
"iteration",
|
|
191
|
+
"inlined",
|
|
192
|
+
"removed",
|
|
193
|
+
"added",
|
|
194
|
+
"instances",
|
|
195
|
+
"changed",
|
|
196
|
+
"scale",
|
|
197
|
+
]
|
|
198
|
+
if c in df.columns
|
|
199
|
+
]
|
|
200
|
+
agg = {k: "sum" for k in cols if k not in ("level", "pattern")}
|
|
201
|
+
agg.update(dict(iteration="max", instances="mean"))
|
|
202
|
+
agg = {k: v for k, v in agg.items() if k in df.columns}
|
|
203
|
+
stat_filename = f"{os.path.splitext(filename)[0]}.opt.agg.xlsx"
|
|
204
|
+
df[cols].groupby(["level", "pattern"]).agg(agg).to_excel(stat_filename)
|
|
205
|
+
|
|
206
|
+
return proto
|
|
160
207
|
|
|
161
208
|
if exporter in ("dynamo", "onnx-dynamo"):
|
|
162
|
-
import os
|
|
163
209
|
from ..helpers import flatten_object
|
|
164
210
|
import onnxscript.rewriter.ort_fusions as ort_fusions
|
|
165
211
|
|
|
@@ -226,7 +272,6 @@ def to_onnx(
|
|
|
226
272
|
return epo
|
|
227
273
|
|
|
228
274
|
if exporter == "modelbuilder":
|
|
229
|
-
import os
|
|
230
275
|
from ..helpers import flatten_object, string_type
|
|
231
276
|
from ..helpers.model_builder_helper import create_model_builder, save_model_builder
|
|
232
277
|
|
|
@@ -267,3 +312,247 @@ def to_onnx(
|
|
|
267
312
|
return onx
|
|
268
313
|
|
|
269
314
|
raise ValueError(f"Unknown exporter={exporter!r}")
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class _WrapperToExportMethodToOnnx(torch.nn.Module):
|
|
318
|
+
"""
|
|
319
|
+
Wraps an existing models in order to spy on inputs.
|
|
320
|
+
This is used by :func:`onnx_diagnostic.export.api.method_to_onnx`.
|
|
321
|
+
"""
|
|
322
|
+
|
|
323
|
+
def __init__(
|
|
324
|
+
self,
|
|
325
|
+
mod: "torch.nn.Module",
|
|
326
|
+
method_name: str = "forward",
|
|
327
|
+
input_names: Optional[Sequence[str]] = None,
|
|
328
|
+
target_opset: Optional[Union[int, Dict[str, int]]] = None,
|
|
329
|
+
verbose: int = 0,
|
|
330
|
+
filename: Optional[str] = None,
|
|
331
|
+
output_names: Optional[List[str]] = None,
|
|
332
|
+
output_dynamic_shapes: Optional[Union[Dict[str, Any], Tuple[Any]]] = None,
|
|
333
|
+
exporter: str = "onnx-dynamo",
|
|
334
|
+
exporter_kwargs: Optional[Dict[str, Any]] = None,
|
|
335
|
+
save_ep: Optional[str] = None,
|
|
336
|
+
optimize: bool = True,
|
|
337
|
+
optimizer_for_ort: bool = True,
|
|
338
|
+
use_control_flow_dispatcher: bool = False,
|
|
339
|
+
onnx_plugs: Optional[List[EagerDirectReplacementWithOnnx]] = None,
|
|
340
|
+
inline: bool = True,
|
|
341
|
+
convert_after_n_calls: int = 2,
|
|
342
|
+
patch_kwargs: Optional[Dict[str, Any]] = None,
|
|
343
|
+
skip_kwargs_names: Optional[Set[str]] = None,
|
|
344
|
+
dynamic_shapes: Optional[Union[Dict[str, Any], Tuple[Any]]] = None,
|
|
345
|
+
):
|
|
346
|
+
super().__init__()
|
|
347
|
+
self._model_to_call = mod
|
|
348
|
+
self._method_name = method_name
|
|
349
|
+
self._method_call = (
|
|
350
|
+
self._model_to_call.forward
|
|
351
|
+
if method_name == "forward"
|
|
352
|
+
else getattr(mod, method_name)
|
|
353
|
+
)
|
|
354
|
+
self._inputs: List[Tuple[Tuple[Any, ...], Dict[str, Any]]] = []
|
|
355
|
+
self._convert_after_n_calls = convert_after_n_calls
|
|
356
|
+
self._patch_kwargs = patch_kwargs
|
|
357
|
+
self._method_src = None
|
|
358
|
+
self.verbose = verbose
|
|
359
|
+
self.skip_kwargs_names = skip_kwargs_names
|
|
360
|
+
self.dynamic_shapes = dynamic_shapes
|
|
361
|
+
self._to_onnx_kwargs = dict(
|
|
362
|
+
input_names=input_names,
|
|
363
|
+
target_opset=target_opset,
|
|
364
|
+
verbose=verbose,
|
|
365
|
+
filename=filename,
|
|
366
|
+
output_names=output_names,
|
|
367
|
+
output_dynamic_shapes=output_dynamic_shapes,
|
|
368
|
+
exporter=exporter,
|
|
369
|
+
exporter_kwargs=exporter_kwargs,
|
|
370
|
+
save_ep=save_ep,
|
|
371
|
+
optimize=optimize,
|
|
372
|
+
optimizer_for_ort=optimizer_for_ort,
|
|
373
|
+
use_control_flow_dispatcher=use_control_flow_dispatcher,
|
|
374
|
+
onnx_plugs=onnx_plugs,
|
|
375
|
+
inline=inline,
|
|
376
|
+
)
|
|
377
|
+
self._export_done = False
|
|
378
|
+
|
|
379
|
+
def __str__(self) -> str:
|
|
380
|
+
return self.__repr__()
|
|
381
|
+
|
|
382
|
+
def __repr__(self) -> str:
|
|
383
|
+
return (
|
|
384
|
+
f"{self.__class__.__name__}({self._model_to_call.__class__.__name__}."
|
|
385
|
+
f"{self._method_name})"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
def forward(self, *args, **kwargs):
|
|
389
|
+
if not self._export_done:
|
|
390
|
+
self._inputs.append(
|
|
391
|
+
(
|
|
392
|
+
args,
|
|
393
|
+
(
|
|
394
|
+
kwargs
|
|
395
|
+
if not kwargs or not self.skip_kwargs_names
|
|
396
|
+
else {
|
|
397
|
+
k: v for k, v in kwargs.items() if k not in self.skip_kwargs_names
|
|
398
|
+
}
|
|
399
|
+
),
|
|
400
|
+
)
|
|
401
|
+
)
|
|
402
|
+
if self.verbose:
|
|
403
|
+
print(
|
|
404
|
+
f"[method_to_onnx] input[{len(self._inputs)-1}]: "
|
|
405
|
+
f"{string_type(self._inputs[-1], with_shape=True)}"
|
|
406
|
+
)
|
|
407
|
+
if len(self._inputs) >= self._convert_after_n_calls:
|
|
408
|
+
self._convert_method_to_onnx()
|
|
409
|
+
del self._inputs[:]
|
|
410
|
+
self._export_done = True
|
|
411
|
+
return self._method_call(*args, **kwargs)
|
|
412
|
+
|
|
413
|
+
def _convert_method_to_onnx(self):
|
|
414
|
+
|
|
415
|
+
def make_method(self):
|
|
416
|
+
inner_sig = inspect.signature(self._method_call)
|
|
417
|
+
params = [
|
|
418
|
+
p.replace(annotation=inspect._empty) for p in inner_sig.parameters.values()
|
|
419
|
+
]
|
|
420
|
+
simple_sig = inspect.Signature(params, return_annotation=inspect._empty)
|
|
421
|
+
args = str(simple_sig)[1:-1]
|
|
422
|
+
calls_args = ", ".join(f"{p}={p}" for p in simple_sig.parameters)
|
|
423
|
+
src = textwrap.dedent(
|
|
424
|
+
f"""
|
|
425
|
+
def f(self, {args}):
|
|
426
|
+
return self._method_call({calls_args})
|
|
427
|
+
"""
|
|
428
|
+
)
|
|
429
|
+
self._method_src = src
|
|
430
|
+
ns = {}
|
|
431
|
+
try:
|
|
432
|
+
exec(src, ns)
|
|
433
|
+
except NameError as e:
|
|
434
|
+
raise NameError(f"Unable to compile due to {e}\n{src}") from e
|
|
435
|
+
return ns["f"]
|
|
436
|
+
|
|
437
|
+
class WrapWithExactSignature(torch.nn.Module):
|
|
438
|
+
def __init__(self, parent):
|
|
439
|
+
super().__init__()
|
|
440
|
+
self._model_to_call = parent._model_to_call
|
|
441
|
+
self._method_call = parent._method_call
|
|
442
|
+
|
|
443
|
+
forward = make_method(self)
|
|
444
|
+
|
|
445
|
+
compiled_model = WrapWithExactSignature(self)
|
|
446
|
+
|
|
447
|
+
if self.dynamic_shapes is None:
|
|
448
|
+
mi = ModelInputs(compiled_model, self._inputs)
|
|
449
|
+
ds = mi.guess_dynamic_shapes()
|
|
450
|
+
if self.verbose:
|
|
451
|
+
print(f"[method_to_onnx] guess_dynamic_shapes={string_type(ds)}")
|
|
452
|
+
a, kw, nds = mi.move_to_kwargs(*self._inputs[-1], ds)
|
|
453
|
+
else:
|
|
454
|
+
a, kw = self._inputs[-1]
|
|
455
|
+
nds = [self.dynamic_shapes]
|
|
456
|
+
if self.verbose:
|
|
457
|
+
print(f"[method_to_onnx] export args={string_type(a, with_shape=True)}")
|
|
458
|
+
print(f"[method_to_onnx] export kwargs={string_type(kw, with_shape=True)}")
|
|
459
|
+
print(f"[method_to_onnx] dynamic_shapes={string_type(nds)}")
|
|
460
|
+
if self._patch_kwargs is None:
|
|
461
|
+
to_onnx(
|
|
462
|
+
compiled_model,
|
|
463
|
+
args=a,
|
|
464
|
+
kwargs=kw,
|
|
465
|
+
dynamic_shapes=nds[-1],
|
|
466
|
+
**self._to_onnx_kwargs,
|
|
467
|
+
)
|
|
468
|
+
return
|
|
469
|
+
from ..torch_export_patches import torch_export_patches
|
|
470
|
+
|
|
471
|
+
with torch_export_patches(**self._patch_kwargs):
|
|
472
|
+
to_onnx(
|
|
473
|
+
compiled_model,
|
|
474
|
+
args=a,
|
|
475
|
+
kwargs=kw,
|
|
476
|
+
dynamic_shapes=nds[-1],
|
|
477
|
+
**self._to_onnx_kwargs,
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def method_to_onnx(
|
|
482
|
+
mod: "torch.nn.Module",
|
|
483
|
+
method_name: str = "forward",
|
|
484
|
+
input_names: Optional[Sequence[str]] = None,
|
|
485
|
+
target_opset: Optional[Union[int, Dict[str, int]]] = None,
|
|
486
|
+
verbose: int = 0,
|
|
487
|
+
filename: Optional[str] = None,
|
|
488
|
+
output_names: Optional[List[str]] = None,
|
|
489
|
+
output_dynamic_shapes: Optional[Union[Dict[str, Any], Tuple[Any]]] = None,
|
|
490
|
+
exporter: str = "onnx-dynamo",
|
|
491
|
+
exporter_kwargs: Optional[Dict[str, Any]] = None,
|
|
492
|
+
save_ep: Optional[str] = None,
|
|
493
|
+
optimize: bool = True,
|
|
494
|
+
optimizer_for_ort: bool = True,
|
|
495
|
+
use_control_flow_dispatcher: bool = False,
|
|
496
|
+
onnx_plugs: Optional[List[EagerDirectReplacementWithOnnx]] = None,
|
|
497
|
+
inline: bool = True,
|
|
498
|
+
convert_after_n_calls: int = 2,
|
|
499
|
+
patch_kwargs: Optional[Dict[str, Any]] = None,
|
|
500
|
+
skip_kwargs_names: Optional[Set[str]] = None,
|
|
501
|
+
dynamic_shapes: Optional[Union[Dict[str, Any], Tuple[Any]]] = None,
|
|
502
|
+
) -> Callable:
|
|
503
|
+
"""
|
|
504
|
+
Exports one method into ONNX for a module into ONNX.
|
|
505
|
+
It returns a new method which must be called by the user
|
|
506
|
+
at least twice with different values for the dynamic dimension
|
|
507
|
+
between triggering the conversion into ONNX.
|
|
508
|
+
|
|
509
|
+
:param mod_meth: function to export into ONNX
|
|
510
|
+
:param input_names: input names for the onnx model (optional)
|
|
511
|
+
:param target_opset: opset to target, if not specified, each converter
|
|
512
|
+
keeps its default value
|
|
513
|
+
:param verbose: verbosity level
|
|
514
|
+
:param filename: output filename, mandatory, the onnx model is saved on disk
|
|
515
|
+
:param output_names: to change the output of the onnx model
|
|
516
|
+
:param output_dynamic_shapes: to overwrite the dynamic shapes names
|
|
517
|
+
:param exporter: exporter to use (``onnx-dynamo``, ``modelbuilder``, ``custom``)
|
|
518
|
+
:param exporter_kwargs: additional parameters sent to the exporter
|
|
519
|
+
:param save_ep: saves the exported program
|
|
520
|
+
:param optimize: optimizes the model
|
|
521
|
+
:param optimizer_for_ort: optimizes the model for onnxruntime
|
|
522
|
+
:param use_control_flow_dispatcher: use the dispatcher created to supported
|
|
523
|
+
custom loops (see :func:`onnx_diagnostic.export.control_flow_onnx.loop_for_onnx`)
|
|
524
|
+
:param onnx_plugs: the code was modified to replace some parts with onnx translation
|
|
525
|
+
:param inline: inline local functions
|
|
526
|
+
:param convert_after_n_calls: converts the model after this number of calls.
|
|
527
|
+
:param patch_kwargs: patch arguments
|
|
528
|
+
:param skip_kwargs_names: use default values for these parameters part of
|
|
529
|
+
the signature of the method to export
|
|
530
|
+
:param dynamic_shapes: dynamic shapes to use if the guessed ones are not right
|
|
531
|
+
:return: the output of the selected exporter, usually a structure including
|
|
532
|
+
an onnx model
|
|
533
|
+
|
|
534
|
+
See :ref:`l-plot-tiny-llm-export-method-generate` for an example.
|
|
535
|
+
"""
|
|
536
|
+
wrapped_model = _WrapperToExportMethodToOnnx(
|
|
537
|
+
mod=mod,
|
|
538
|
+
method_name=method_name,
|
|
539
|
+
input_names=input_names,
|
|
540
|
+
target_opset=target_opset,
|
|
541
|
+
verbose=verbose,
|
|
542
|
+
filename=filename,
|
|
543
|
+
output_names=output_names,
|
|
544
|
+
output_dynamic_shapes=output_dynamic_shapes,
|
|
545
|
+
exporter=exporter,
|
|
546
|
+
exporter_kwargs=exporter_kwargs,
|
|
547
|
+
save_ep=save_ep,
|
|
548
|
+
optimize=optimize,
|
|
549
|
+
optimizer_for_ort=optimizer_for_ort,
|
|
550
|
+
use_control_flow_dispatcher=use_control_flow_dispatcher,
|
|
551
|
+
onnx_plugs=onnx_plugs,
|
|
552
|
+
inline=inline,
|
|
553
|
+
convert_after_n_calls=convert_after_n_calls,
|
|
554
|
+
patch_kwargs=patch_kwargs,
|
|
555
|
+
skip_kwargs_names=skip_kwargs_names,
|
|
556
|
+
dynamic_shapes=dynamic_shapes,
|
|
557
|
+
)
|
|
558
|
+
return wrapped_model
|
|
@@ -352,6 +352,19 @@ class CoupleInputsDynamicShapes:
|
|
|
352
352
|
else None
|
|
353
353
|
)
|
|
354
354
|
assert type(inputs) is dict, f"Unexpected type for inputs {type(inputs)}"
|
|
355
|
+
if set(inputs) != set(ds):
|
|
356
|
+
not_in_ds = {k for k in inputs if k not in ds}
|
|
357
|
+
not_in_inputs = {k for k in ds if k not in inputs}
|
|
358
|
+
assert not_in_inputs == {"kwargs"} and set(ds["kwargs"]) == not_in_ds, (
|
|
359
|
+
f"Keys mismatch between inputs {set(inputs)} and ds={set(ds)}, "
|
|
360
|
+
f"inputs={string_type(inputs, with_shape=True)}, ds={ds}, "
|
|
361
|
+
f"not_in_ds={not_in_ds}, not_in_inputs={not_in_inputs}"
|
|
362
|
+
)
|
|
363
|
+
# Tweak...
|
|
364
|
+
kws = ds["kwargs"]
|
|
365
|
+
del ds["kwargs"]
|
|
366
|
+
ds.update(kws)
|
|
367
|
+
|
|
355
368
|
assert set(inputs) == set(ds), (
|
|
356
369
|
f"Keys mismatch between inputs {set(inputs)} and ds={set(ds)}, "
|
|
357
370
|
f"inputs={string_type(inputs, with_shape=True)}, ds={ds}"
|
|
@@ -366,13 +379,15 @@ class CoupleInputsDynamicShapes:
|
|
|
366
379
|
return dvalue if dvalue else None
|
|
367
380
|
|
|
368
381
|
# A custom class.
|
|
369
|
-
assert inputs.__class__ in torch.utils._pytree.SUPPORTED_NODES, (
|
|
382
|
+
assert inputs is None or inputs.__class__ in torch.utils._pytree.SUPPORTED_NODES, (
|
|
370
383
|
f"Class {inputs.__class__.__name__!r} was not registered using "
|
|
371
384
|
f"torch.utils._pytree.register_pytree_node, it is not possible to "
|
|
372
385
|
f"map this class with the given dynamic shapes."
|
|
373
386
|
)
|
|
374
387
|
if flatten_unflatten:
|
|
375
388
|
flatunflat = flatten_unflatten_for_dynamic_shapes(inputs)
|
|
389
|
+
if isinstance(flatunflat, (list, tuple, dict)) and len(flatunflat) == 0:
|
|
390
|
+
return flatunflat
|
|
376
391
|
res = cls._generic_walker_step(
|
|
377
392
|
processor, flatunflat, ds, flatten_unflatten=flatten_unflatten
|
|
378
393
|
)
|
|
@@ -667,6 +682,11 @@ class ModelInputs:
|
|
|
667
682
|
if self.signature
|
|
668
683
|
else None
|
|
669
684
|
)
|
|
685
|
+
self.forward_parameters_kinds = (
|
|
686
|
+
{p.name: p.kind for p in self.signature.parameters.values()}
|
|
687
|
+
if self.signature
|
|
688
|
+
else None
|
|
689
|
+
)
|
|
670
690
|
self.forward_ordered_parameter_names = (
|
|
671
691
|
list(self.signature.parameters) if self.signature else None
|
|
672
692
|
)
|
|
@@ -973,7 +993,13 @@ class ModelInputs:
|
|
|
973
993
|
len(s1) == 1
|
|
974
994
|
), f"Different numbers of positional arguments {s1} for {self.full_name}"
|
|
975
995
|
s2 = set(tuple(sorted(set(i[1]))) for i in self.inputs)
|
|
976
|
-
assert len(s2)
|
|
996
|
+
assert len(s2) > 0, f"empty {s2} for {self.full_name}"
|
|
997
|
+
if len(s2) > 1:
|
|
998
|
+
# We need to keep the largest set of inputs, the one including all the others.
|
|
999
|
+
sum_s2 = set()
|
|
1000
|
+
for s in s2:
|
|
1001
|
+
sum_s2 |= set(s)
|
|
1002
|
+
s2 = {tuple(sum_s2)}
|
|
977
1003
|
args = []
|
|
978
1004
|
kwargs = {}
|
|
979
1005
|
for i in range(s1.pop()):
|
|
@@ -993,12 +1019,18 @@ class ModelInputs:
|
|
|
993
1019
|
f"\ninputs[1]={string_type(self.inputs[1], with_shape=True)}"
|
|
994
1020
|
)
|
|
995
1021
|
|
|
996
|
-
objs = [_[1][name] for _ in self.inputs]
|
|
1022
|
+
objs = [_[1][name] for _ in self.inputs if name in _[1]]
|
|
997
1023
|
kwargs[name] = self.guess_dynamic_shape_object(
|
|
998
1024
|
*objs,
|
|
999
1025
|
auto=auto if isinstance(auto, bool) else f"{auto}_{i}I",
|
|
1000
1026
|
msg=lambda name=name: f" failing input {name!r}",
|
|
1001
1027
|
)
|
|
1028
|
+
# reordering
|
|
1029
|
+
if kwargs is not None and self.forward_ordered_parameter_names:
|
|
1030
|
+
kwargs1 = {
|
|
1031
|
+
p: kwargs[p] for p in self.forward_ordered_parameter_names if p in kwargs
|
|
1032
|
+
}
|
|
1033
|
+
kwargs = {**kwargs1, **{k: v for k, v in kwargs.items() if k not in kwargs1}}
|
|
1002
1034
|
return tuple(args), kwargs
|
|
1003
1035
|
|
|
1004
1036
|
def move_to_kwargs(
|
|
@@ -1061,6 +1093,16 @@ class ModelInputs:
|
|
|
1061
1093
|
f"and kwargs={set(kwargs)}, "
|
|
1062
1094
|
f"forward_ordered_parameter_names={self.forward_ordered_parameter_names}"
|
|
1063
1095
|
)
|
|
1096
|
+
if kwargs is not None and self.forward_ordered_parameter_names:
|
|
1097
|
+
kwargs1 = {
|
|
1098
|
+
p: kwargs[p] for p in self.forward_ordered_parameter_names if p in kwargs
|
|
1099
|
+
}
|
|
1100
|
+
kwargs = {**kwargs1, **{k: v for k, v in kwargs.items() if k not in kwargs1}}
|
|
1101
|
+
if kw_dyn is not None and self.forward_ordered_parameter_names:
|
|
1102
|
+
kw_dyn1 = {
|
|
1103
|
+
p: kw_dyn[p] for p in self.forward_ordered_parameter_names if p in kw_dyn
|
|
1104
|
+
}
|
|
1105
|
+
kw_dyn = {**kw_dyn1, **{k: v for k, v in kw_dyn.items() if k not in kw_dyn1}}
|
|
1064
1106
|
return args, kwargs, (tuple(), kw_dyn)
|
|
1065
1107
|
|
|
1066
1108
|
def validate_inputs_for_export(
|
|
@@ -210,6 +210,7 @@ def make_fake_with_dynamic_dimensions(
|
|
|
210
210
|
This uses function :func:`onnx_diagnostic.helpers.fake_tensor_helper.make_fake`.
|
|
211
211
|
Parameter ``existing`` is used to reused the same object when the dynamic
|
|
212
212
|
dimension is given the same name as another one.
|
|
213
|
+
This function works with caches only if ``transformers>=4.57``.
|
|
213
214
|
|
|
214
215
|
A simple tensor:
|
|
215
216
|
|
|
@@ -28,14 +28,6 @@ class CacheKeyValue:
|
|
|
28
28
|
]
|
|
29
29
|
self.key_cache = [layer.keys for layer in layers]
|
|
30
30
|
self.value_cache = [layer.values for layer in layers]
|
|
31
|
-
if None in self.key_cache or None in self.value_cache:
|
|
32
|
-
from .helper import string_type
|
|
33
|
-
|
|
34
|
-
raise AssertionError(
|
|
35
|
-
f"issue with key_cache={string_type(self.key_cache)}, "
|
|
36
|
-
f"or value_cache={string_type(self.value_cache)}, "
|
|
37
|
-
f"cache.layers={string_type(cache.layers)}"
|
|
38
|
-
)
|
|
39
31
|
elif cache is not None and hasattr(cache, "key_cache"):
|
|
40
32
|
self.key_cache = cache.key_cache
|
|
41
33
|
self.value_cache = cache.value_cache
|
|
@@ -105,6 +105,8 @@ class FakeTensorContext:
|
|
|
105
105
|
reduced_tensor = self.from_tensor(true_tensor, static_shapes=True).sum(
|
|
106
106
|
axis=tuple(sorted(sh)), keepdim=True
|
|
107
107
|
)
|
|
108
|
+
if len(reduced_tensor.shape) == 0 == len(new_shape):
|
|
109
|
+
return reduced_tensor
|
|
108
110
|
return reduced_tensor.expand(*new_shape)
|
|
109
111
|
|
|
110
112
|
def make_fake(self, x: Any) -> Optional["FakeTensor"]: # noqa: F821
|
|
@@ -144,19 +146,22 @@ class FakeTensorContext:
|
|
|
144
146
|
"""
|
|
145
147
|
See
|
|
146
148
|
:func:`onnx_diagnostic.export.shape_helper.make_fake_with_dynamic_dimensions`.
|
|
149
|
+
If caches are used, it requires ``transformers>=4.57``.
|
|
147
150
|
"""
|
|
148
151
|
if x is None:
|
|
149
152
|
return None, None
|
|
150
|
-
if
|
|
153
|
+
if type(x) in (list, tuple):
|
|
151
154
|
return x.__class__(
|
|
152
155
|
[
|
|
153
156
|
self.make_fake_with_dynamic_dimensions(i, dynamic_shapes=ds)
|
|
154
157
|
for i, ds in zip(x, dynamic_shapes)
|
|
155
158
|
]
|
|
156
159
|
)
|
|
157
|
-
if
|
|
160
|
+
if type(x) is dict:
|
|
158
161
|
return {
|
|
159
|
-
k: self.make_fake_with_dynamic_dimensions(
|
|
162
|
+
k: self.make_fake_with_dynamic_dimensions(
|
|
163
|
+
v, dynamic_shapes=dynamic_shapes[k] if dynamic_shapes else None
|
|
164
|
+
)
|
|
160
165
|
for k, v in x.items()
|
|
161
166
|
}
|
|
162
167
|
if x.__class__.__name__ in {"DynamicCache", "StaticCache", "HybridCache"}:
|
|
@@ -187,6 +192,17 @@ class FakeTensorContext:
|
|
|
187
192
|
x.cross_attention_cache, dynamic_shapes=dynamic_shapes[1]
|
|
188
193
|
)
|
|
189
194
|
return x
|
|
195
|
+
if x.__class__.__name__ == "BaseModelOutput":
|
|
196
|
+
assert (
|
|
197
|
+
list(x.keys()) == ["last_hidden_state"] and x.last_hidden_state is not None
|
|
198
|
+
), (
|
|
199
|
+
f"Field 'last_hidden_state' is empty for {type(x)} or other fields "
|
|
200
|
+
f"{list(x.keys())} are used."
|
|
201
|
+
)
|
|
202
|
+
x.last_hidden_state = self.make_fake_with_dynamic_dimensions(
|
|
203
|
+
x.last_hidden_state, dynamic_shapes=dynamic_shapes[0]
|
|
204
|
+
)
|
|
205
|
+
return x
|
|
190
206
|
if hasattr(x, "shape"):
|
|
191
207
|
assert dynamic_shapes is None or isinstance(dynamic_shapes, dict), (
|
|
192
208
|
f"dynamic_shapes must be a dictionary at this stage but "
|
|
@@ -197,9 +213,11 @@ class FakeTensorContext:
|
|
|
197
213
|
for idim, dim in enumerate(x.shape):
|
|
198
214
|
if dynamic_shapes is not None and idim in dynamic_shapes:
|
|
199
215
|
s = dynamic_shapes[idim]
|
|
216
|
+
if s.__class__.__name__ == "Dim":
|
|
217
|
+
s = s.__name__
|
|
200
218
|
assert isinstance(s, str), (
|
|
201
219
|
f"Unexpected type {type(s)} in dynamic_shapes={dynamic_shapes} "
|
|
202
|
-
f"at index {idim}"
|
|
220
|
+
f"at index {idim}, self._mapping_str={self._mapping_str}"
|
|
203
221
|
)
|
|
204
222
|
if s in self._mapping_str:
|
|
205
223
|
dim = self._mapping_str[s]
|
|
@@ -217,10 +235,13 @@ class FakeTensorContext:
|
|
|
217
235
|
|
|
218
236
|
x = torch.empty(tuple(new_shape), dtype=x.dtype, device=x.device)
|
|
219
237
|
|
|
220
|
-
t = self.fake_reshape(x, dynamic_shapes) # type: ignore[arg-type]
|
|
238
|
+
t = self.fake_reshape(x, dynamic_shapes) if dynamic_shapes else x # type: ignore[arg-type]
|
|
221
239
|
assert t.device == x.device, f"device mismatch {x.device} -> {t.device}"
|
|
222
240
|
assert t.dtype == x.dtype, f"dtype mismatch {x.dtype} -> {t.dtype}"
|
|
223
241
|
return t
|
|
242
|
+
if isinstance(x, (int, bool, float)):
|
|
243
|
+
# It is a constant, we don't change that.
|
|
244
|
+
return x
|
|
224
245
|
from ..helpers import string_type
|
|
225
246
|
|
|
226
247
|
raise TypeError(
|
|
@@ -704,9 +704,35 @@ def string_type(
|
|
|
704
704
|
if obj.__class__.__name__ == "VirtualTensor":
|
|
705
705
|
if verbose:
|
|
706
706
|
print(f"[string_type] TT4:{type(obj)}")
|
|
707
|
+
|
|
708
|
+
def _torch_sym_int_to_str(value: "torch.SymInt") -> Union[int, str]: # noqa: F821
|
|
709
|
+
if isinstance(value, str):
|
|
710
|
+
return value
|
|
711
|
+
if hasattr(value, "node") and isinstance(value.node, str):
|
|
712
|
+
return f"{value.node}"
|
|
713
|
+
|
|
714
|
+
from torch.fx.experimental.sym_node import SymNode
|
|
715
|
+
|
|
716
|
+
if hasattr(value, "node") and isinstance(value.node, SymNode):
|
|
717
|
+
# '_expr' is safer than expr
|
|
718
|
+
return str(value.node._expr).replace(" ", "")
|
|
719
|
+
|
|
720
|
+
try:
|
|
721
|
+
val_int = int(value)
|
|
722
|
+
return val_int
|
|
723
|
+
except (
|
|
724
|
+
TypeError,
|
|
725
|
+
ValueError,
|
|
726
|
+
AttributeError,
|
|
727
|
+
torch.fx.experimental.symbolic_shapes.GuardOnDataDependentSymNode,
|
|
728
|
+
):
|
|
729
|
+
pass
|
|
730
|
+
|
|
731
|
+
raise AssertionError(f"Unable to convert {value!r} into string")
|
|
732
|
+
|
|
707
733
|
return (
|
|
708
734
|
f"{obj.__class__.__name__}(name={obj.name!r}, "
|
|
709
|
-
f"dtype={obj.dtype}, shape={obj.shape})"
|
|
735
|
+
f"dtype={obj.dtype}, shape={tuple(_torch_sym_int_to_str(_) for _ in obj.shape)})"
|
|
710
736
|
)
|
|
711
737
|
|
|
712
738
|
if obj.__class__.__name__ == "KeyValuesWrapper":
|
|
@@ -775,6 +801,9 @@ def string_type(
|
|
|
775
801
|
print(f"[string_type] TT8:{type(obj)}")
|
|
776
802
|
return repr(obj).replace(" ", "").replace("\n", " ")
|
|
777
803
|
|
|
804
|
+
if isinstance(obj, torch.fx.proxy.Proxy):
|
|
805
|
+
return repr(obj)
|
|
806
|
+
|
|
778
807
|
if ignore:
|
|
779
808
|
if verbose:
|
|
780
809
|
print(f"[string_type] CACHE4:{type(obj)}")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
2
3
|
import onnx
|
|
3
4
|
import numpy as np
|
|
@@ -76,6 +77,10 @@ class _InferenceSession:
|
|
|
76
77
|
session_options.enable_profiling = enable_profiling
|
|
77
78
|
if optimized_model_filepath:
|
|
78
79
|
session_options.optimized_model_filepath = optimized_model_filepath
|
|
80
|
+
session_options.add_session_config_entry(
|
|
81
|
+
"session.optimized_model_external_initializers_file_name",
|
|
82
|
+
f"{os.path.splitext(os.path.split(optimized_model_filepath)[-1])[0]}.data",
|
|
83
|
+
)
|
|
79
84
|
if log_severity_level is not None:
|
|
80
85
|
session_options.log_severity_level = log_severity_level
|
|
81
86
|
if log_verbosity_level is not None:
|
|
@@ -172,10 +172,10 @@ def _get_inputs_gemma3(
|
|
|
172
172
|
assert expected & set(
|
|
173
173
|
dummies
|
|
174
174
|
), f"Unable to find expected inputs {expected} in loaded inputs {set(dummies)}"
|
|
175
|
-
assert sequence_length == dummies["input_ids"].shape[-1], (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
175
|
+
# assert sequence_length == dummies["input_ids"].shape[-1], (
|
|
176
|
+
# f"sequence_length={sequence_length} != {dummies['input_ids'].shape[-1]} for "
|
|
177
|
+
# f"model class {model.__class__.__name__}"
|
|
178
|
+
# )
|
|
179
179
|
assert batch_size == dummies["input_ids"].shape[0], (
|
|
180
180
|
f"batch_size={batch_size} != {dummies['input_ids'].shape[0]} for "
|
|
181
181
|
f"model class {model.__class__.__name__}"
|
|
@@ -191,7 +191,7 @@ class PatchDetails:
|
|
|
191
191
|
ep = torch.export.export(
|
|
192
192
|
model, (), kwargs=inputs, dynamic_shapes=use_dyn_not_str(ds)
|
|
193
193
|
)
|
|
194
|
-
patches = details.
|
|
194
|
+
patches = details.patches_involved_in_graph(ep.graph)
|
|
195
195
|
report = details.make_report(patches, format="rst")
|
|
196
196
|
print(report)
|
|
197
197
|
"""
|
|
@@ -235,7 +235,7 @@ class PatchDetails:
|
|
|
235
235
|
"""Returns the data for a dataframe."""
|
|
236
236
|
return [p.to_dict() for p in self.patched]
|
|
237
237
|
|
|
238
|
-
def
|
|
238
|
+
def patches_involved_in_graph(
|
|
239
239
|
self, graph: "torch.fx.Graph" # noqa: F821
|
|
240
240
|
) -> List[Tuple[PatchInfo, List["torch.fx.Node"]]]: # noqa: F821
|
|
241
241
|
"""
|
|
@@ -322,7 +322,7 @@ class PatchDetails:
|
|
|
322
322
|
"""
|
|
323
323
|
Creates a report based on the involved patches.
|
|
324
324
|
|
|
325
|
-
:param patches: from method :meth:`
|
|
325
|
+
:param patches: from method :meth:`patches_involved_in_graph`
|
|
326
326
|
:param format: format of the report
|
|
327
327
|
:return: report
|
|
328
328
|
"""
|
|
@@ -22,13 +22,22 @@ if patch_DynamicLayer:
|
|
|
22
22
|
_PATCHES_ = ["lazy_initialization"]
|
|
23
23
|
_PATCHED_CLASS_ = DynamicLayer
|
|
24
24
|
|
|
25
|
-
def lazy_initialization(
|
|
25
|
+
def lazy_initialization(
|
|
26
|
+
self, key_states: torch.Tensor, value_states: torch.Tensor = None
|
|
27
|
+
):
|
|
26
28
|
self.dtype, self.device = key_states.dtype, key_states.device
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
assert (
|
|
30
|
+
hasattr(key_states, "shape") and key_states is not None
|
|
31
|
+
), f"Attribute 'shape' is wrong for type {type(key_states)}"
|
|
32
|
+
like = torch.narrow(key_states, dim=-2, start=0, length=0)
|
|
29
33
|
# PATCHED: used a tensor with an empty shape and not en empty list to initialize
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
if isinstance(key_states, torch._subclasses.fake_tensor.FakeTensor):
|
|
35
|
+
with key_states.fake_mode:
|
|
36
|
+
self.keys = torch.empty_like(like, dtype=self.dtype, device=self.device)
|
|
37
|
+
self.values = torch.empty_like(like, dtype=self.dtype, device=self.device)
|
|
38
|
+
else:
|
|
39
|
+
self.keys = torch.empty_like(like, dtype=self.dtype, device=self.device)
|
|
40
|
+
self.values = torch.empty_like(like, dtype=self.dtype, device=self.device)
|
|
32
41
|
if patch_is_initialized:
|
|
33
42
|
self.is_initialized = True
|
|
34
43
|
|
|
@@ -214,7 +214,7 @@ def patched_dynamic_rope_update(rope_forward):
|
|
|
214
214
|
cond,
|
|
215
215
|
(lambda x, y: x.clone()),
|
|
216
216
|
(lambda x, y: y.clone()),
|
|
217
|
-
[long_inv_freq, original_inv_freq],
|
|
217
|
+
[long_inv_freq.to(original_inv_freq.dtype), original_inv_freq],
|
|
218
218
|
)
|
|
219
219
|
setattr(self, f"{prefix}inv_freq", inv_freq)
|
|
220
220
|
# if seq_len > original_max_position_embeddings:
|
|
@@ -293,7 +293,7 @@ def patched_dynamic_rope_update(rope_forward):
|
|
|
293
293
|
cond,
|
|
294
294
|
(lambda x, y: x.clone()),
|
|
295
295
|
(lambda x, y: y.clone()),
|
|
296
|
-
[long_inv_freq, original_inv_freq],
|
|
296
|
+
[long_inv_freq.to(original_inv_freq.dtype), original_inv_freq],
|
|
297
297
|
)
|
|
298
298
|
setattr(self, f"{prefix}inv_freq", inv_freq)
|
|
299
299
|
|
|
@@ -1771,6 +1771,10 @@ def validate_onnx_model(
|
|
|
1771
1771
|
if os.environ.get("DUMPORTOPT", "") in ("1", "true", "True"):
|
|
1772
1772
|
opts = onnxruntime.SessionOptions()
|
|
1773
1773
|
opts.optimized_model_filepath = f"{data['onnx_filename']}.rtopt.onnx"
|
|
1774
|
+
opts.add_session_config_entry(
|
|
1775
|
+
"session.optimized_model_external_initializers_file_name",
|
|
1776
|
+
f"{os.path.split(data['onnx_filename'])[0]}.rtopt.data",
|
|
1777
|
+
)
|
|
1774
1778
|
if verbose:
|
|
1775
1779
|
print(
|
|
1776
1780
|
f"[validate_onnx_model] saved optimized onnxruntime "
|
|
@@ -2326,6 +2330,7 @@ def call_torch_export_custom(
|
|
|
2326
2330
|
"custom-dec",
|
|
2327
2331
|
"custom-decall",
|
|
2328
2332
|
"custom-fake",
|
|
2333
|
+
"custom-tracing",
|
|
2329
2334
|
}
|
|
2330
2335
|
assert exporter in available, f"Unexpected value for exporter={exporter!r} in {available}"
|
|
2331
2336
|
assert "model" in data, f"model is missing from data: {sorted(data)}"
|
|
@@ -2338,11 +2343,16 @@ def call_torch_export_custom(
|
|
|
2338
2343
|
f"Options strict cannot be specified in the exporter name {exporter!r} "
|
|
2339
2344
|
f"and in the options {exporter_options}"
|
|
2340
2345
|
)
|
|
2346
|
+
assert ("-tracing" not in exporter) or ("tracing" not in exporter_options), (
|
|
2347
|
+
f"Options tracing cannot be specified in the exporter name {exporter!r} "
|
|
2348
|
+
f"and in the options {exporter_options}"
|
|
2349
|
+
)
|
|
2341
2350
|
summary: Dict[str, Union[str, int, float]] = {}
|
|
2342
2351
|
strict = "-strict" in exporter or exporter_options.pop("strict", False)
|
|
2343
2352
|
args, kwargs = split_args_kwargs(data["inputs_export"])
|
|
2344
2353
|
ds = data.get("dynamic_shapes", None)
|
|
2345
2354
|
fake = "-fake" in exporter or exporter_options.pop("fake", False)
|
|
2355
|
+
tracing = "-tracing" in exporter or exporter_options.pop("tracing", False)
|
|
2346
2356
|
if fake:
|
|
2347
2357
|
from onnx_diagnostic.export.shape_helper import make_fake_with_dynamic_dimensions
|
|
2348
2358
|
|
|
@@ -2366,6 +2376,7 @@ def call_torch_export_custom(
|
|
|
2366
2376
|
summary["export_exporter"] = exporter
|
|
2367
2377
|
summary["export_optimization"] = optimization or ""
|
|
2368
2378
|
summary["export_strict"] = strict
|
|
2379
|
+
summary["export_tracing"] = tracing
|
|
2369
2380
|
summary["export_fake"] = fake
|
|
2370
2381
|
summary["export_args"] = string_type(args, with_shape=True)
|
|
2371
2382
|
summary["export_kwargs"] = string_type(kwargs, with_shape=True)
|
|
@@ -2388,6 +2399,7 @@ def call_torch_export_custom(
|
|
|
2388
2399
|
)
|
|
2389
2400
|
)
|
|
2390
2401
|
large_model = bool(exporter_options.pop("large_model", True))
|
|
2402
|
+
exporter_options.pop("tracing", False)
|
|
2391
2403
|
return_optimize_report = bool(exporter_options.pop("return_optimize_report", True))
|
|
2392
2404
|
export_modules_as_functions = bool(
|
|
2393
2405
|
exporter_options.pop("export_modules_as_functions", False)
|
|
@@ -2401,6 +2413,7 @@ def call_torch_export_custom(
|
|
|
2401
2413
|
summary["export_external_threshold"] = str(external_threshold)
|
|
2402
2414
|
|
|
2403
2415
|
export_options = ExportOptions(
|
|
2416
|
+
tracing=tracing,
|
|
2404
2417
|
strict=strict,
|
|
2405
2418
|
decomposition_table=decomposition_table,
|
|
2406
2419
|
save_ep=(
|
|
@@ -2445,6 +2458,41 @@ def call_torch_export_custom(
|
|
|
2445
2458
|
)
|
|
2446
2459
|
),
|
|
2447
2460
|
)
|
|
2461
|
+
if "optimization" in opt_stats and dump_folder:
|
|
2462
|
+
import pandas
|
|
2463
|
+
|
|
2464
|
+
pattern_stats = []
|
|
2465
|
+
for k, v in opt_stats.items():
|
|
2466
|
+
if "time" in k:
|
|
2467
|
+
pattern_stats.append(dict(level="main", pattern=k, time_in=v))
|
|
2468
|
+
pattern_stats.extend(
|
|
2469
|
+
[{**obs, "level": "detailed"} for obs in opt_stats["optimization"]]
|
|
2470
|
+
)
|
|
2471
|
+
stat_filename = os.path.join(dump_folder, "optimization_stats.xlsx")
|
|
2472
|
+
df = pandas.DataFrame(pattern_stats)
|
|
2473
|
+
df.to_excel(stat_filename, index=False)
|
|
2474
|
+
cols = [
|
|
2475
|
+
c
|
|
2476
|
+
for c in [
|
|
2477
|
+
"level",
|
|
2478
|
+
"pattern",
|
|
2479
|
+
"time_in",
|
|
2480
|
+
"iteration",
|
|
2481
|
+
"inlined",
|
|
2482
|
+
"removed",
|
|
2483
|
+
"added",
|
|
2484
|
+
"instances",
|
|
2485
|
+
"changed",
|
|
2486
|
+
"scale",
|
|
2487
|
+
]
|
|
2488
|
+
if c in df.columns
|
|
2489
|
+
]
|
|
2490
|
+
agg = {k: "sum" for k in cols if k not in ("level", "pattern")}
|
|
2491
|
+
agg.update(dict(iteration="max", instances="mean"))
|
|
2492
|
+
agg = {k: v for k, v in agg.items() if k in df.columns}
|
|
2493
|
+
stat_filename = os.path.join(dump_folder, "optimization_stats.agg.xlsx")
|
|
2494
|
+
df[cols].groupby(["level", "pattern"]).agg(agg).to_excel(stat_filename)
|
|
2495
|
+
|
|
2448
2496
|
if "ERR_export_onnx_c" in summary:
|
|
2449
2497
|
return summary, data
|
|
2450
2498
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onnx-diagnostic
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.8
|
|
4
4
|
Summary: Tools to help converting pytorch models into ONNX.
|
|
5
5
|
Home-page: https://github.com/sdpython/onnx-diagnostic
|
|
6
6
|
Author: Xavier Dupré
|
|
@@ -90,6 +90,8 @@ Enlightening Examples
|
|
|
90
90
|
|
|
91
91
|
* `Export microsoft/phi-2
|
|
92
92
|
<https://sdpython.github.io/doc/onnx-diagnostic/dev/auto_examples/plot_export_tiny_phi2.html>`_
|
|
93
|
+
* `Export a model through method generate (with Tiny-LLM)
|
|
94
|
+
<https://sdpython.github.io/doc/onnx-diagnostic/dev/auto_examples/plot_export_tiny_llm_method_generate.html>`_
|
|
93
95
|
|
|
94
96
|
**Torch Export**
|
|
95
97
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
onnx_diagnostic/__init__.py,sha256=
|
|
1
|
+
onnx_diagnostic/__init__.py,sha256=Is5g4yyLoruIq2F94HTISS_8sTf8w9AHzf6qlhhytZ0,173
|
|
2
2
|
onnx_diagnostic/__main__.py,sha256=YmyV_Aq_ianDlHyKLHMa6h8YK3ZmFPpLVHLKjM91aCk,79
|
|
3
3
|
onnx_diagnostic/_command_lines_parser.py,sha256=g_udwHBHmY6X_d41Qby_DqMpEHL1p9GfUhJGBCihl8c,57784
|
|
4
4
|
onnx_diagnostic/api.py,sha256=BhCl_yCd78N7TlVtPOHjeYv1QBEy39TjZ647rcHqLh0,345
|
|
@@ -6,34 +6,34 @@ onnx_diagnostic/doc.py,sha256=t3RELgfooYnVMAi0JSpggWkQEgUsREz8NmRvn0TnLI8,2829
|
|
|
6
6
|
onnx_diagnostic/ext_test_case.py,sha256=A6BkrRm-QbvM8A-qRRMLt9o9ZO6wMXE9jrotggjpGfE,50460
|
|
7
7
|
onnx_diagnostic/ci_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
onnx_diagnostic/ci_models/ci_helpers.py,sha256=lblOF7z2kLcCRAwMOdqp-Tz1EL1oBywHfVokhqiTQRg,15592
|
|
9
|
-
onnx_diagnostic/ci_models/export_phi4_mm.py,sha256=
|
|
9
|
+
onnx_diagnostic/ci_models/export_phi4_mm.py,sha256=DH225jXhOG_S8KZE9Kn7FGNE4VqFyc9ZDnG-qxZn-hk,41668
|
|
10
10
|
onnx_diagnostic/ci_models/export_qwen25_vl.py,sha256=_rYPr8PPraWizr2MPcGuYjrJ55ilJOyKl8kg0wq4L90,20405
|
|
11
11
|
onnx_diagnostic/export/__init__.py,sha256=yEIoWiOeTwBsDhyYt2fTKuhtA0Ya1J9u9ZzMTOTWaWs,101
|
|
12
|
-
onnx_diagnostic/export/api.py,sha256=
|
|
12
|
+
onnx_diagnostic/export/api.py,sha256=V-2IhcxfMRFIh-CBb3c7QUUTcd_11FjRLHXLhIOy4Fk,22111
|
|
13
13
|
onnx_diagnostic/export/cf_simple_loop_for.py,sha256=OHPGQc9AC-0TBtCYpP6cm-iHP9gmNt8WYRrPlO9ewlc,21158
|
|
14
14
|
onnx_diagnostic/export/control_flow_onnx.py,sha256=izGlctqQANrHzSxPMbT7hoauNbnIBdx6hb8ry7HtVmM,18263
|
|
15
|
-
onnx_diagnostic/export/dynamic_shapes.py,sha256=
|
|
15
|
+
onnx_diagnostic/export/dynamic_shapes.py,sha256=z6BgCAHyrB6SLcCdjy5CMr8lOy-dm-CUQgJc_GyQVTw,44138
|
|
16
16
|
onnx_diagnostic/export/onnx_plug.py,sha256=U13fL0BjnhMzcDGxaAOqM4TQte5Z4zKDg4ESS0iktjM,22704
|
|
17
|
-
onnx_diagnostic/export/shape_helper.py,sha256=
|
|
17
|
+
onnx_diagnostic/export/shape_helper.py,sha256=L0RKUufLQDM5PqDMYk-9L3YZMnv4Zpz2t18KL_37RUU,11341
|
|
18
18
|
onnx_diagnostic/export/validate.py,sha256=_PGUql2DJhIgGKo0WjTGUc5AgsZUx8fEs00MePy-w98,6043
|
|
19
19
|
onnx_diagnostic/helpers/__init__.py,sha256=GJ2GT7cgnlIveVUwMZhuvUwidbTJaKv8CsSIOpZDsJg,83
|
|
20
20
|
onnx_diagnostic/helpers/_log_helper.py,sha256=OTwQH0OIxs9B6nrSvR7MoxMimSw_8mU0mj133NvLk5o,16832
|
|
21
21
|
onnx_diagnostic/helpers/args_helper.py,sha256=SRWnqC7EENg09RZlA50B_PcdiIhdbgA4C3ACfzl5nMs,4419
|
|
22
22
|
onnx_diagnostic/helpers/bench_run.py,sha256=Vvzb7Wy0baIT5O0dx4RKQTx-5V08PiHxPJh6XPkY-lU,16544
|
|
23
|
-
onnx_diagnostic/helpers/cache_helper.py,sha256=
|
|
23
|
+
onnx_diagnostic/helpers/cache_helper.py,sha256=RsPuYRQ_RiA4I-J2loD-gXnmLsvxskp_nqv_C9hQlrU,28114
|
|
24
24
|
onnx_diagnostic/helpers/config_helper.py,sha256=cWRETgFhZ7tayIZPnMqF8BF5AvTU64G2BMqyzgO7lzs,5670
|
|
25
25
|
onnx_diagnostic/helpers/doc_helper.py,sha256=pl5MZd3_FaE8BqQnqoBuSBxoNCFcd2OJd3eITUSku5c,5897
|
|
26
26
|
onnx_diagnostic/helpers/dot_helper.py,sha256=hwgTJsbsUv0qq7euyPDnc1NsBZDGOwv32JXSZxIHJkE,8118
|
|
27
|
-
onnx_diagnostic/helpers/fake_tensor_helper.py,sha256=
|
|
27
|
+
onnx_diagnostic/helpers/fake_tensor_helper.py,sha256=59046wDIw84or6PJxLaa2CFqaWT7Y3mpYr-BB2shcBE,12027
|
|
28
28
|
onnx_diagnostic/helpers/graph_helper.py,sha256=hevQT5a7_QuriVPQcbT5qe18n99Doyl5h3-qshx1-uk,14093
|
|
29
|
-
onnx_diagnostic/helpers/helper.py,sha256=
|
|
29
|
+
onnx_diagnostic/helpers/helper.py,sha256=Fa5wB0CAva2d82RDjCoJxbf1AafYWPZEHKlyz7PZLg0,66505
|
|
30
30
|
onnx_diagnostic/helpers/log_helper.py,sha256=3mWQd-nLKCctKZt9N8SpoWgLC8O7YdNQ2pfW5QXYWDQ,93232
|
|
31
31
|
onnx_diagnostic/helpers/memory_peak.py,sha256=M3m4_thWFIwP5HytbJYEqaijXIv5v5BW_vlcJowIYI4,6434
|
|
32
32
|
onnx_diagnostic/helpers/mini_onnx_builder.py,sha256=jR2lkRZEQ0N30H0FqeBwaxJd_w_6kyxFagrnulqFjhE,23883
|
|
33
33
|
onnx_diagnostic/helpers/model_builder_helper.py,sha256=qKIq4Naqq03gk6NfqXLQjSDiKL5FFNc1AEyVX0R8GmA,18540
|
|
34
34
|
onnx_diagnostic/helpers/onnx_helper.py,sha256=MshvqMSTNUUZIpkkRYGDymdW2t2KtB2BgYtOPHIDwvQ,57508
|
|
35
35
|
onnx_diagnostic/helpers/optim_helper.py,sha256=0NiYRwV9GLTub4SEny0dqEhLcajRjEhcgkeBDVr9bGQ,4424
|
|
36
|
-
onnx_diagnostic/helpers/ort_session.py,sha256=
|
|
36
|
+
onnx_diagnostic/helpers/ort_session.py,sha256=Y6iJojJcQtPesy9dRaaxRSeRTLXk0Pdh6-_fzdiPDm0,30779
|
|
37
37
|
onnx_diagnostic/helpers/rt_helper.py,sha256=OOxHSCKZup2u7zTvVJxPkRHb4jQZ03KpkiDGrfwibMM,38135
|
|
38
38
|
onnx_diagnostic/helpers/torch_fx_graph_helper.py,sha256=7xFe4svdbr4gV3OTNcx8eJejjDyHAv4hD_RNNKSxL0c,6571
|
|
39
39
|
onnx_diagnostic/helpers/torch_helper.py,sha256=ADV81WWCskQ-jmzn1GI_LU8GqBtufCHS3oeLG-3Uw0E,38954
|
|
@@ -89,7 +89,7 @@ onnx_diagnostic/tasks/automatic_speech_recognition.py,sha256=aMufLDGW005f7aLMZ9a
|
|
|
89
89
|
onnx_diagnostic/tasks/feature_extraction.py,sha256=IS9z9fPNE0hhGUebBfmNZl0twdXobMc7MFKpQB9qZI0,5388
|
|
90
90
|
onnx_diagnostic/tasks/fill_mask.py,sha256=5Gt6zlj0p6vuifox7Wmj-TpHXJvPS0CEH8evgdBHDNA,2640
|
|
91
91
|
onnx_diagnostic/tasks/image_classification.py,sha256=nLpBBB1Gkog3Fk6pu2waiHcuQr4ILPptc9FhQ-pn460,4682
|
|
92
|
-
onnx_diagnostic/tasks/image_text_to_text.py,sha256=
|
|
92
|
+
onnx_diagnostic/tasks/image_text_to_text.py,sha256=A3mg3t7zh2Z_kAJ4cQBrW9x6O1knMPjL_LwMlH78m-k,22142
|
|
93
93
|
onnx_diagnostic/tasks/image_to_video.py,sha256=SoF2cVIJr6P30Abp-FCuixFDh5RvTuNEOL36QthGY6U,3860
|
|
94
94
|
onnx_diagnostic/tasks/mask_generation.py,sha256=fjdD3rd-O-mFL0hQy3la3JXKth_0bH2HL7Eelq-3Dbs,5057
|
|
95
95
|
onnx_diagnostic/tasks/mixture_of_expert.py,sha256=al4tk1BrHidtRiHlAaiflWiJaAte0d5M8WcBioANG9k,2808
|
|
@@ -106,7 +106,7 @@ onnx_diagnostic/tasks/data/dummies_imagetext2text_generation_gemma3.onnx,sha256=
|
|
|
106
106
|
onnx_diagnostic/torch_export_patches/__init__.py,sha256=0SaZedwznm1hQUCvXZsGZORV5vby954wEExr5faepGg,720
|
|
107
107
|
onnx_diagnostic/torch_export_patches/onnx_export_errors.py,sha256=XHYtU7w3vsaTMCuF5X1YtOKxgwL8eEuktXzVZpRz55o,43431
|
|
108
108
|
onnx_diagnostic/torch_export_patches/onnx_export_serialization.py,sha256=0HdubI06EGpxOICqDWZoVmZkVO9gAaFADEmby197EyM,11935
|
|
109
|
-
onnx_diagnostic/torch_export_patches/patch_details.py,sha256=
|
|
109
|
+
onnx_diagnostic/torch_export_patches/patch_details.py,sha256=UHBo4QTLF3ZgQ4951yYHIQqxOeRYNaG7x56XFcRTtg4,11794
|
|
110
110
|
onnx_diagnostic/torch_export_patches/patch_expressions.py,sha256=VOsv71FsR_UZtxz4-5_VKL2sHQhOkHy9RkPJME2h7UU,3271
|
|
111
111
|
onnx_diagnostic/torch_export_patches/patch_inputs.py,sha256=-TgcyjVzxTb5Y-_ibssTeaA5PFz6FJrV6q84HMUAsJw,8075
|
|
112
112
|
onnx_diagnostic/torch_export_patches/patch_module.py,sha256=1Mn3xdpK1jSdRs6z1C-mJGkfGmD2TNRwLNoPaOW_EFI,40061
|
|
@@ -117,7 +117,7 @@ onnx_diagnostic/torch_export_patches/patches/__init__.py,sha256=47DEQpj8HBSa-_TI
|
|
|
117
117
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_attention.py,sha256=5JOyT95BNwHIuxaSFJDSEGsoI-6IwbgNnFwg2q3UM-Q,7731
|
|
118
118
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_cache_utils.py,sha256=UdxLii-od2OpQmUJbmXmZinXeLBItVFrr75BVT1Y0zw,2041
|
|
119
119
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_causal_mask.py,sha256=h37DPVxsq8iAWECnTlKW5tVqSBgPBF52xr3uxsjdi2k,3113
|
|
120
|
-
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_dynamic_cache.py,sha256=
|
|
120
|
+
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_dynamic_cache.py,sha256=aiRtT1SUTrH7wYpBF7YjPEgb-fRYXlnilims4Y5a0JA,8516
|
|
121
121
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_funnel.py,sha256=QAMFiA8MGQgbowZzpfLsh7gXTuzXc3eGmZ7hLKF1i78,3352
|
|
122
122
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_gemma3.py,sha256=nVgYQk0xXpHiictN1wOHVMN2lTH9b0vfIJ4ie-uKopg,1999
|
|
123
123
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_generation_mixin.py,sha256=VIZsVHgR8NmAcBQalPl5I6ZzNgcBxjGb6ars31m9gRg,21936
|
|
@@ -126,7 +126,7 @@ onnx_diagnostic/torch_export_patches/patches/_patch_transformers_masking_utils.p
|
|
|
126
126
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_qwen2.py,sha256=OxYdlLrwtd_KGHt3E17poduxvWFg-CfGS57-yN1i6gI,3827
|
|
127
127
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_qwen2_5.py,sha256=oYz0tr-6KH0DabpgaISytnXAGxQosoA8gV5LpksO4yI,34834
|
|
128
128
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_qwen3.py,sha256=cND9Iqo1aKdlX-BXGr9Qlq_Y4EW1L5VWSwZfqYTVazU,4888
|
|
129
|
-
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_rotary_embedding.py,sha256=
|
|
129
|
+
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_rotary_embedding.py,sha256=LAqoL5SWISekZO15G1HIcCkN1JlBxGqb9XbK_eLzalA,16949
|
|
130
130
|
onnx_diagnostic/torch_export_patches/patches/_patch_transformers_sam_mask_decoder.py,sha256=-6TuBm3sLAFEGuW3vRfOTtE5uP6aINFfu7xMnl27Dws,5703
|
|
131
131
|
onnx_diagnostic/torch_export_patches/patches/patch_helper.py,sha256=kK_CGW643iVXxa-m6pttDBS7HTyMQaPypza7iqIInn4,721
|
|
132
132
|
onnx_diagnostic/torch_export_patches/patches/patch_torch.py,sha256=VCs3uZHcuzosCqn9sSEskEWHJym_RrDJM6-G6FcTC08,45117
|
|
@@ -137,7 +137,7 @@ onnx_diagnostic/torch_export_patches/serialization/transformers_impl.py,sha256=s
|
|
|
137
137
|
onnx_diagnostic/torch_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
138
|
onnx_diagnostic/torch_models/code_sample.py,sha256=rCDZY64pkn6uIbJJSBuC5TlU_-uleI73I9GlbXtJd54,12923
|
|
139
139
|
onnx_diagnostic/torch_models/llms.py,sha256=soyg4yC87ptGoeulJhKqw5opGmuLvH1pn_ZDXZ4Jr8E,90
|
|
140
|
-
onnx_diagnostic/torch_models/validate.py,sha256=
|
|
140
|
+
onnx_diagnostic/torch_models/validate.py,sha256=JsEMv7aeg9tGGriKZ_CJeqGDfNUmZNdGtPu5jQN9TWY,96739
|
|
141
141
|
onnx_diagnostic/torch_models/hghub/__init__.py,sha256=vi1Q7YHdddj1soiBN42MSvJdFqe2_KUoWafHISjwOu8,58
|
|
142
142
|
onnx_diagnostic/torch_models/hghub/hub_api.py,sha256=V3azxUqb7mkmHQ8m5DCgg1WUU2NYBK12USEUy_sfYIA,14709
|
|
143
143
|
onnx_diagnostic/torch_models/hghub/hub_data.py,sha256=6jR8A83cGP4Xw1Wg-q1zzKFpqzoVrybqm0Fm3yurkrE,9030
|
|
@@ -152,8 +152,8 @@ onnx_diagnostic/torch_onnx/compare.py,sha256=O0lws4kzn8WAXr8-x-YMPr7oyBC9DtSIs4O
|
|
|
152
152
|
onnx_diagnostic/torch_onnx/runtime_info.py,sha256=u1bD6VXqzBCRmqmbzQtDswaPs1PH_ygr1r-CrcfXpNU,8562
|
|
153
153
|
onnx_diagnostic/torch_onnx/sbs.py,sha256=8okBEIupMgw7TtKc80YFimMtwnY3GchdY05FsA9ooa0,40749
|
|
154
154
|
onnx_diagnostic/torch_onnx/sbs_dataclasses.py,sha256=UctdBjzoPTQG1LS0tZ8A6E9hpoq5HWUYaJLPOPJc9FI,20299
|
|
155
|
-
onnx_diagnostic-0.8.
|
|
156
|
-
onnx_diagnostic-0.8.
|
|
157
|
-
onnx_diagnostic-0.8.
|
|
158
|
-
onnx_diagnostic-0.8.
|
|
159
|
-
onnx_diagnostic-0.8.
|
|
155
|
+
onnx_diagnostic-0.8.8.dist-info/licenses/LICENSE.txt,sha256=Vv6TXglX6Rc0d-f8aREhayhT-6PMQXEyOmI2NKlUCMc,1045
|
|
156
|
+
onnx_diagnostic-0.8.8.dist-info/METADATA,sha256=sxPBIjOSLqQITi527dnl_3gk3RxT9kNCu47gPPyrg7Q,6905
|
|
157
|
+
onnx_diagnostic-0.8.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
158
|
+
onnx_diagnostic-0.8.8.dist-info/top_level.txt,sha256=KwNkXewmcobM3ZT1DJLVWH6ebJzA5qKg7cWqKfpGNT4,16
|
|
159
|
+
onnx_diagnostic-0.8.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|