onnx-diagnostic 0.6.3__py3-none-any.whl → 0.7.1__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 (44) hide show
  1. onnx_diagnostic/__init__.py +1 -1
  2. onnx_diagnostic/_command_lines_parser.py +281 -80
  3. onnx_diagnostic/doc.py +22 -0
  4. onnx_diagnostic/export/dynamic_shapes.py +48 -20
  5. onnx_diagnostic/export/shape_helper.py +126 -0
  6. onnx_diagnostic/ext_test_case.py +1 -1
  7. onnx_diagnostic/helpers/cache_helper.py +78 -8
  8. onnx_diagnostic/helpers/config_helper.py +8 -4
  9. onnx_diagnostic/helpers/helper.py +30 -3
  10. onnx_diagnostic/helpers/log_helper.py +1744 -0
  11. onnx_diagnostic/helpers/mini_onnx_builder.py +4 -1
  12. onnx_diagnostic/helpers/model_builder_helper.py +54 -73
  13. onnx_diagnostic/helpers/torch_helper.py +18 -2
  14. onnx_diagnostic/reference/__init__.py +1 -0
  15. onnx_diagnostic/reference/ort_evaluator.py +29 -4
  16. onnx_diagnostic/reference/report_results_comparison.py +95 -0
  17. onnx_diagnostic/reference/torch_evaluator.py +21 -0
  18. onnx_diagnostic/tasks/automatic_speech_recognition.py +3 -0
  19. onnx_diagnostic/tasks/feature_extraction.py +3 -0
  20. onnx_diagnostic/tasks/fill_mask.py +3 -0
  21. onnx_diagnostic/tasks/image_classification.py +7 -1
  22. onnx_diagnostic/tasks/image_text_to_text.py +72 -18
  23. onnx_diagnostic/tasks/mixture_of_expert.py +3 -0
  24. onnx_diagnostic/tasks/object_detection.py +3 -0
  25. onnx_diagnostic/tasks/sentence_similarity.py +3 -0
  26. onnx_diagnostic/tasks/summarization.py +3 -0
  27. onnx_diagnostic/tasks/text2text_generation.py +3 -0
  28. onnx_diagnostic/tasks/text_classification.py +3 -0
  29. onnx_diagnostic/tasks/text_generation.py +90 -43
  30. onnx_diagnostic/tasks/zero_shot_image_classification.py +3 -0
  31. onnx_diagnostic/torch_export_patches/onnx_export_errors.py +78 -25
  32. onnx_diagnostic/torch_export_patches/onnx_export_serialization.py +37 -0
  33. onnx_diagnostic/torch_export_patches/patches/patch_transformers.py +365 -17
  34. onnx_diagnostic/torch_models/hghub/hub_api.py +81 -8
  35. onnx_diagnostic/torch_models/hghub/hub_data.py +6 -2
  36. onnx_diagnostic/torch_models/hghub/hub_data_cached_configs.py +209 -0
  37. onnx_diagnostic/torch_models/hghub/model_inputs.py +58 -14
  38. onnx_diagnostic/torch_models/untrained/llm_tiny_llm.py +23 -50
  39. onnx_diagnostic/torch_models/{test_helper.py → validate.py} +166 -106
  40. {onnx_diagnostic-0.6.3.dist-info → onnx_diagnostic-0.7.1.dist-info}/METADATA +2 -2
  41. {onnx_diagnostic-0.6.3.dist-info → onnx_diagnostic-0.7.1.dist-info}/RECORD +44 -41
  42. {onnx_diagnostic-0.6.3.dist-info → onnx_diagnostic-0.7.1.dist-info}/WHEEL +0 -0
  43. {onnx_diagnostic-0.6.3.dist-info → onnx_diagnostic-0.7.1.dist-info}/licenses/LICENSE.txt +0 -0
  44. {onnx_diagnostic-0.6.3.dist-info → onnx_diagnostic-0.7.1.dist-info}/top_level.txt +0 -0
@@ -3,5 +3,5 @@ Patches, Investigates onnx models.
3
3
  Functions, classes to dig into a model when this one is right, slow, wrong...
4
4
  """
5
5
 
6
- __version__ = "0.6.3"
6
+ __version__ = "0.7.1"
7
7
  __author__ = "Xavier Dupré"
@@ -5,19 +5,18 @@ import re
5
5
  import sys
6
6
  import textwrap
7
7
  import onnx
8
- from typing import Any, List, Optional
8
+ from typing import Any, Dict, List, Optional, Union
9
9
  from argparse import ArgumentParser, RawTextHelpFormatter, BooleanOptionalAction
10
- from textwrap import dedent
11
10
 
12
11
 
13
12
  def get_parser_lighten() -> ArgumentParser:
14
13
  parser = ArgumentParser(
15
14
  prog="lighten",
16
- description=dedent(
15
+ description=textwrap.dedent(
16
+ """
17
+ Removes the weights from a heavy model, stores statistics to restore
18
+ random weights.
17
19
  """
18
- Removes the weights from a heavy model, stores statistics to restore
19
- random weights.
20
- """
21
20
  ),
22
21
  epilog="This is mostly used to write unit tests without adding "
23
22
  "a big onnx file to the repository.",
@@ -70,11 +69,11 @@ def _cmd_lighten(argv: List[Any]):
70
69
  def get_parser_unlighten() -> ArgumentParser:
71
70
  parser = ArgumentParser(
72
71
  prog="unlighten",
73
- description=dedent(
72
+ description=textwrap.dedent(
73
+ """
74
+ Restores random weights for a model reduces with command lighten,
75
+ the command expects to find a file nearby with extension '.stats'.
74
76
  """
75
- Restores random weights for a model reduces with command lighten,
76
- the command expects to find a file nearby with extension '.stats'.
77
- """
78
77
  ),
79
78
  epilog="This is mostly used to write unit tests without adding "
80
79
  "a big onnx file to the repository.",
@@ -120,11 +119,7 @@ def _cmd_unlighten(argv: List[Any]):
120
119
  def get_parser_print() -> ArgumentParser:
121
120
  parser = ArgumentParser(
122
121
  prog="print",
123
- description=dedent(
124
- """
125
- Prints the model on the standard output.
126
- """
127
- ),
122
+ description="Prints the model on the standard output.",
128
123
  epilog="To show a model.",
129
124
  formatter_class=RawTextHelpFormatter,
130
125
  )
@@ -171,11 +166,11 @@ def _cmd_print(argv: List[Any]):
171
166
  def get_parser_find() -> ArgumentParser:
172
167
  parser = ArgumentParser(
173
168
  prog="find",
174
- description=dedent(
169
+ description=textwrap.dedent(
170
+ """
171
+ Look into a model and search for a set of names,
172
+ tells which node is consuming or producing it.
175
173
  """
176
- Look into a model and search for a set of names,
177
- tells which node is consuming or producing it.
178
- """
179
174
  ),
180
175
  epilog="Enables Some quick validation.",
181
176
  )
@@ -191,8 +186,8 @@ def get_parser_find() -> ArgumentParser:
191
186
  "--names",
192
187
  type=str,
193
188
  required=False,
194
- help="names to look at comma separated values, if 'SHADOW', "
195
- "search for shadowing names",
189
+ help="Names to look at comma separated values, if 'SHADOW', "
190
+ "search for shadowing names.",
196
191
  )
197
192
  parser.add_argument(
198
193
  "-v",
@@ -206,7 +201,7 @@ def get_parser_find() -> ArgumentParser:
206
201
  "--v2",
207
202
  default=False,
208
203
  action=BooleanOptionalAction,
209
- help="use enumerate_results instead of onnx_find",
204
+ help="Uses enumerate_results instead of onnx_find.",
210
205
  )
211
206
  return parser
212
207
 
@@ -235,12 +230,13 @@ def _cmd_find(argv: List[Any]):
235
230
  def get_parser_config() -> ArgumentParser:
236
231
  parser = ArgumentParser(
237
232
  prog="config",
238
- description=dedent(
233
+ description=textwrap.dedent(
234
+ """
235
+ Prints out a configuration for a model id,
236
+ prints the associated task as well.
239
237
  """
240
- Prints out a configuration for a model id,
241
- prints the associated task as well.
242
- """
243
238
  ),
239
+ formatter_class=RawTextHelpFormatter,
244
240
  epilog="",
245
241
  )
246
242
  parser.add_argument(
@@ -248,29 +244,29 @@ def get_parser_config() -> ArgumentParser:
248
244
  "--mid",
249
245
  type=str,
250
246
  required=True,
251
- help="model id, usually <author>/<name>",
247
+ help="model id, usually `<author>/<name>`",
252
248
  )
253
249
  parser.add_argument(
254
250
  "-t",
255
251
  "--task",
256
252
  default=False,
257
253
  action=BooleanOptionalAction,
258
- help="displays the task as well",
254
+ help="Displays the task as well.",
259
255
  )
260
256
  parser.add_argument(
261
257
  "-c",
262
258
  "--cached",
263
259
  default=True,
264
260
  action=BooleanOptionalAction,
265
- help="uses cached configuration, only available for some of them, "
266
- "mostly for unit test purposes",
261
+ help="Uses cached configuration, only available for some of them,\n"
262
+ "mostly for unit test purposes.",
267
263
  )
268
264
  parser.add_argument(
269
265
  "--mop",
270
266
  metavar="KEY=VALUE",
271
267
  nargs="*",
272
268
  help="Additional model options, use to change some parameters of the model, "
273
- "example: --mop attn_implementation=eager",
269
+ "example:\n --mop attn_implementation=sdpa or --mop attn_implementation=eager",
274
270
  action=_ParseDict,
275
271
  )
276
272
  return parser
@@ -291,6 +287,14 @@ def _cmd_config(argv: List[Any]):
291
287
  print(f"task: {task_from_id(args.mid)}")
292
288
 
293
289
 
290
+ def _parse_json(value: str) -> Union[str, Dict[str, Any]]:
291
+ assert isinstance(value, str), f"value should be string but value={value!r}"
292
+ if value and value[0] == "{" and value[-1] == "}":
293
+ # a dictionary
294
+ return json.loads(value.replace("'", '"'))
295
+ return value
296
+
297
+
294
298
  class _ParseDict(argparse.Action):
295
299
  def __call__(self, parser, namespace, values, option_string=None):
296
300
  d = getattr(namespace, self.dest) or {}
@@ -314,22 +318,40 @@ class _ParseDict(argparse.Action):
314
318
  continue
315
319
  except (TypeError, ValueError):
316
320
  pass
317
- d[key] = value
321
+ d[key] = _parse_json(value)
318
322
 
319
323
  setattr(namespace, self.dest, d)
320
324
 
321
325
 
322
326
  def get_parser_validate() -> ArgumentParser:
323
327
  parser = ArgumentParser(
324
- prog="test",
325
- description=dedent(
328
+ prog="validate",
329
+ description=textwrap.dedent(
330
+ """
331
+ Prints out dummy inputs for a particular task or a model id.
332
+ If both mid and task are empty, the command line displays the list
333
+ of supported tasks.
334
+ """
335
+ ),
336
+ epilog=textwrap.dedent(
337
+ """
338
+ If the model id is specified, one untrained version of it is instantiated.
339
+ Examples:
340
+
341
+ python -m onnx_diagnostic validate -m microsoft/Phi-4-mini-reasoning \\
342
+ --run -v 1 -o dump_test --no-quiet --repeat 2 --warmup 2 \\
343
+ --dtype float16 --device cuda --patch --export onnx-dynamo --opt ir
344
+
345
+ python -m onnx_diagnostic validate -m microsoft/Phi-4-mini-reasoning \\
346
+ --run -v 1 -o dump_test --no-quiet --repeat 2 --warmup 2 \\
347
+ --dtype float16 --device cuda --patch --export custom --opt default
348
+
349
+ python -m onnx_diagnostic validate -m microsoft/Phi-4-mini-reasoning \\
350
+ --run -v 1 -o dump_test --no-quiet --repeat 2 --warmup 2 \\
351
+ --dtype float16 --device cuda --export modelbuilder
326
352
  """
327
- Prints out dummy inputs for a particular task or a model id.
328
- If both mid and task are empty, the command line displays the list
329
- of supported tasks.
330
- """
331
353
  ),
332
- epilog="If the model id is specified, one untrained version of it is instantiated.",
354
+ formatter_class=RawTextHelpFormatter,
333
355
  )
334
356
  parser.add_argument("-m", "--mid", type=str, help="model id, usually <author>/<name>")
335
357
  parser.add_argument("-t", "--task", default=None, help="force the task to use")
@@ -340,55 +362,67 @@ def get_parser_validate() -> ArgumentParser:
340
362
  "--run",
341
363
  default=False,
342
364
  action=BooleanOptionalAction,
343
- help="runs the model to check it runs",
365
+ help="Runs the model to check it runs.",
344
366
  )
345
367
  parser.add_argument(
346
368
  "-q",
347
369
  "--quiet",
348
370
  default=False,
349
371
  action=BooleanOptionalAction,
350
- help="catches exception, report them in the summary",
372
+ help="Catches exception, reports them in the summary.",
351
373
  )
352
374
  parser.add_argument(
353
375
  "--patch",
354
376
  default=True,
355
377
  action=BooleanOptionalAction,
356
- help="applies patches before exporting",
378
+ help="Applies patches before exporting.",
357
379
  )
358
380
  parser.add_argument(
359
381
  "--rewrite",
360
382
  default=True,
361
383
  action=BooleanOptionalAction,
362
- help="applies rewrite before exporting",
384
+ help="Applies rewrite before exporting.",
363
385
  )
364
386
  parser.add_argument(
365
387
  "--stop-if-static",
366
388
  default=0,
367
389
  type=int,
368
- help="raises an exception if a dynamic dimension becomes static",
390
+ help="Raises an exception if a dynamic dimension becomes static.",
391
+ )
392
+ parser.add_argument(
393
+ "--same-as-trained",
394
+ default=False,
395
+ action=BooleanOptionalAction,
396
+ help="Validates a model identical to the trained model but not trained.",
369
397
  )
370
398
  parser.add_argument(
371
399
  "--trained",
372
400
  default=False,
373
401
  action=BooleanOptionalAction,
374
- help="validate the trained model (requires downloading)",
402
+ help="Validates the trained model (requires downloading).",
403
+ )
404
+ parser.add_argument(
405
+ "--inputs2",
406
+ default=True,
407
+ action=BooleanOptionalAction,
408
+ help="Validates the model on a second set of inputs\n"
409
+ "to check the exported model supports dynamism.",
375
410
  )
376
411
  parser.add_argument(
377
412
  "--runtime",
378
413
  choices=["onnxruntime", "torch", "ref"],
379
414
  default="onnxruntime",
380
- help="onnx runtime to use, onnxruntime by default",
415
+ help="onnx runtime to use, `onnxruntime` by default",
381
416
  )
382
417
  parser.add_argument(
383
418
  "-o",
384
419
  "--dump-folder",
385
- help="if not empty, a folder is created to dumps statistics, "
386
- "exported program, onnx...",
420
+ help="A folder is created to dumps statistics,\nexported program, onnx...",
387
421
  )
388
422
  parser.add_argument(
389
423
  "--drop",
390
- help="drops the following inputs names, it should be a list "
391
- "with comma separated values",
424
+ help="Drops the following inputs names, it should be a list\n"
425
+ "with comma separated values.",
392
426
  )
393
427
  parser.add_argument(
394
428
  "--opset",
@@ -398,24 +432,25 @@ def get_parser_validate() -> ArgumentParser:
398
432
  )
399
433
  parser.add_argument(
400
434
  "--subfolder",
401
- help="subfolder where to find the model and the configuration",
435
+ help="Subfolder where to find the model and the configuration.",
402
436
  )
403
437
  parser.add_argument(
404
438
  "--ortfusiontype",
405
439
  required=False,
406
- help="applies onnxruntime fusion, this parameter should contain the "
407
- "model type or multiple values separated by `|`. `ALL` can be used "
408
- "to run them all",
440
+ help="Applies onnxruntime fusion, this parameter should contain the\n"
441
+ "model type or multiple values separated by `|`. `ALL` can be used\n"
442
+ "to run them all.",
409
443
  )
410
444
  parser.add_argument("-v", "--verbose", default=0, type=int, help="verbosity")
411
- parser.add_argument("--dtype", help="changes dtype if necessary")
412
- parser.add_argument("--device", help="changes the device if necessary")
445
+ parser.add_argument("--dtype", help="Changes dtype if necessary.")
446
+ parser.add_argument("--device", help="Changes the device if necessary.")
413
447
  parser.add_argument(
414
448
  "--iop",
415
449
  metavar="KEY=VALUE",
416
450
  nargs="*",
417
- help="Additional input options, use to change the default "
418
- "inputs use to export, example: --iop cls_cache=SlidingWindowCache",
451
+ help="Additional input options, use to change the default"
452
+ "inputs use to export, example:\n --iop cls_cache=SlidingWindowCache"
453
+ "\n --iop cls_cache=StaticCache",
419
454
  action=_ParseDict,
420
455
  )
421
456
  parser.add_argument(
@@ -423,7 +458,8 @@ def get_parser_validate() -> ArgumentParser:
423
458
  metavar="KEY=VALUE",
424
459
  nargs="*",
425
460
  help="Additional model options, use to change some parameters of the model, "
426
- "example: --mop attn_implementation=eager",
461
+ "example:\n --mop attn_implementation=sdpa --mop attn_implementation=eager\n "
462
+ "--mop \"rope_scaling={'rope_type': 'dynamic', 'factor': 10.0}\"",
427
463
  action=_ParseDict,
428
464
  )
429
465
  parser.add_argument(
@@ -440,7 +476,7 @@ def get_parser_validate() -> ArgumentParser:
440
476
 
441
477
  def _cmd_validate(argv: List[Any]):
442
478
  from .helpers import string_type
443
- from .torch_models.test_helper import get_inputs_for_task, validate_model
479
+ from .torch_models.validate import get_inputs_for_task, validate_model
444
480
  from .tasks import supported_tasks
445
481
 
446
482
  parser = get_parser_validate()
@@ -474,7 +510,8 @@ def _cmd_validate(argv: List[Any]):
474
510
  do_run=args.run,
475
511
  verbose=args.verbose,
476
512
  quiet=args.quiet,
477
- trained=args.trained,
513
+ same_as_pretrained=args.same_as_trained,
514
+ use_pretrained=args.trained,
478
515
  dtype=args.dtype,
479
516
  device=args.device,
480
517
  patch=args.patch,
@@ -492,6 +529,7 @@ def _cmd_validate(argv: List[Any]):
492
529
  runtime=args.runtime,
493
530
  repeat=args.repeat,
494
531
  warmup=args.warmup,
532
+ inputs2=args.inputs2,
495
533
  )
496
534
  print("")
497
535
  print("-- summary --")
@@ -502,11 +540,7 @@ def _cmd_validate(argv: List[Any]):
502
540
  def get_parser_stats() -> ArgumentParser:
503
541
  parser = ArgumentParser(
504
542
  prog="stats",
505
- description=dedent(
506
- """
507
- Prints out statistics on an ONNX model.
508
- """
509
- ),
543
+ description="Prints out statistics on an ONNX model.",
510
544
  epilog="",
511
545
  )
512
546
  parser.add_argument(
@@ -553,8 +587,8 @@ def get_parser_stats() -> ArgumentParser:
553
587
  required=False,
554
588
  default="",
555
589
  type=str,
556
- help="keeps only tensors whose name verifies "
557
- "this regular expression, empty = no filter",
590
+ help="Keeps only tensors whose name verifies "
591
+ "this regular expression, empty = no filter.",
558
592
  )
559
593
  return parser
560
594
 
@@ -599,6 +633,161 @@ def _cmd_stats(argv: List[Any]):
599
633
  print("done.")
600
634
 
601
635
 
636
+ def get_parser_agg() -> ArgumentParser:
637
+ parser = ArgumentParser(
638
+ prog="agg",
639
+ description=textwrap.dedent(
640
+ """
641
+ Aggregates statistics coming from benchmarks.
642
+ Every run is a row. Every row is indexed by some keys,
643
+ and produces values. Every row has a date.
644
+ """
645
+ ),
646
+ epilog=textwrap.dedent(
647
+ """
648
+ examples:\n
649
+
650
+ python -m onnx_diagnostic agg test_agg.xlsx raw/*.zip -v 1
651
+ """
652
+ ),
653
+ formatter_class=RawTextHelpFormatter,
654
+ )
655
+ parser.add_argument("output", help="output excel file")
656
+ parser.add_argument(
657
+ "inputs",
658
+ nargs="+",
659
+ help="input csv or zip files, at least 1, it can be a name, or search path",
660
+ )
661
+ parser.add_argument(
662
+ "--filter", default="rawdata_.*.csv", help="filter for input files inside zip files"
663
+ )
664
+ parser.add_argument(
665
+ "--recent",
666
+ default=True,
667
+ action=BooleanOptionalAction,
668
+ help="Keeps only the most recent experiment for the same of keys.",
669
+ )
670
+ parser.add_argument(
671
+ "--keep-last-date",
672
+ default=False,
673
+ action=BooleanOptionalAction,
674
+ help="Rewrite all dates to the last one to simplifies the analysis, "
675
+ "this assume changing the date does not add ambiguity, if any, option "
676
+ "--recent should be added.",
677
+ )
678
+ parser.add_argument(
679
+ "--raw",
680
+ default=True,
681
+ action=BooleanOptionalAction,
682
+ help="Keeps the raw data in a sheet.",
683
+ )
684
+ parser.add_argument("-t", "--time", default="DATE", help="Date or time column")
685
+ parser.add_argument(
686
+ "-k",
687
+ "--keys",
688
+ default="^version_.*,^model_.*,device,opt_patterns,suite,memory_peak,"
689
+ "machine,exporter,dynamic,rtopt,dtype,device,architecture",
690
+ help="List of columns to consider as keys, "
691
+ "multiple values are separated by `,`\n"
692
+ "regular expressions are allowed",
693
+ )
694
+ parser.add_argument(
695
+ "--drop-keys",
696
+ default="",
697
+ help="Drops keys from the given list. Something it is faster "
698
+ "to remove one than to select all the remaining ones.",
699
+ )
700
+ parser.add_argument(
701
+ "-w",
702
+ "--values",
703
+ default="^time_.*,^disc.*,^ERR_.*,CMD,^ITER.*,^onnx_.*,^op_onnx_.*,^peak_gpu_.*",
704
+ help="List of columns to consider as values, "
705
+ "multiple values are separated by `,`\n"
706
+ "regular expressions are allowed",
707
+ )
708
+ parser.add_argument(
709
+ "-i", "--ignored", default="^version_.*", help="List of columns to ignore"
710
+ )
711
+ parser.add_argument(
712
+ "-f",
713
+ "--formula",
714
+ default="speedup,bucket[speedup],ERR1,n_models,n_model_eager,"
715
+ "n_model_running,n_model_acc01,n_model_acc001,n_model_dynamic,"
716
+ "n_model_pass,n_model_faster,"
717
+ "n_model_faster2x,n_model_faster3x,n_model_faster4x,n_node_attention,"
718
+ "peak_gpu_torch,peak_gpu_nvidia,n_node_control_flow,"
719
+ "n_node_constant,n_node_shape,n_node_expand,"
720
+ "n_node_function,n_node_initializer,n_node_scatter,"
721
+ "time_export_unbiased",
722
+ help="Columns to compute after the aggregation was done.",
723
+ )
724
+ parser.add_argument(
725
+ "--views",
726
+ default="agg-suite,agg-all,disc,speedup,time,time_export,err,cmd,"
727
+ "bucket-speedup,raw-short,counts,peak-gpu",
728
+ help="Views to add to the output files.",
729
+ )
730
+ parser.add_argument(
731
+ "--csv",
732
+ default="raw-short",
733
+ help="Views to dump as csv files.",
734
+ )
735
+ parser.add_argument("-v", "--verbose", type=int, default=0, help="verbosity")
736
+ return parser
737
+
738
+
739
+ def _cmd_agg(argv: List[Any]):
740
+ from .helpers.log_helper import CubeLogsPerformance, open_dataframe, enumerate_csv_files
741
+
742
+ parser = get_parser_agg()
743
+ args = parser.parse_args(argv[1:])
744
+ reg = re.compile(args.filter)
745
+
746
+ csv = list(
747
+ enumerate_csv_files(
748
+ args.inputs, verbose=args.verbose, filtering=lambda name: bool(reg.search(name))
749
+ )
750
+ )
751
+ assert csv, f"No csv files in {args.inputs}, csv={csv}"
752
+ if args.verbose:
753
+ from tqdm import tqdm
754
+
755
+ loop = tqdm(csv)
756
+ else:
757
+ loop = csv
758
+ dfs = []
759
+ for c in loop:
760
+ df = open_dataframe(c)
761
+ assert (
762
+ args.time in df.columns
763
+ ), f"Missing time column {args.time!r} in {c!r}\n{df.head()}\n{sorted(df.columns)}"
764
+ dfs.append(df)
765
+
766
+ drop_keys = set(args.drop_keys.split(","))
767
+ cube = CubeLogsPerformance(
768
+ dfs,
769
+ time=args.time,
770
+ keys=[a for a in args.keys.split(",") if a and a not in drop_keys],
771
+ values=[a for a in args.values.split(",") if a],
772
+ ignored=[a for a in args.ignored.split(",") if a],
773
+ recent=args.recent,
774
+ formulas={k: k for k in args.formula.split(",")},
775
+ keep_last_date=args.keep_last_date,
776
+ )
777
+ cube.load(verbose=max(args.verbose - 1, 0))
778
+ if args.verbose:
779
+ print(f"Dumps final file into {args.output!r}")
780
+ cube.to_excel(
781
+ args.output,
782
+ {k: k for k in args.views.split(",")},
783
+ verbose=args.verbose,
784
+ csv=args.csv.split(","),
785
+ raw=args.raw,
786
+ )
787
+ if args.verbose:
788
+ print(f"Wrote {args.output!r}")
789
+
790
+
602
791
  def get_main_parser() -> ArgumentParser:
603
792
  parser = ArgumentParser(
604
793
  prog="onnx_diagnostic",
@@ -606,22 +795,32 @@ def get_main_parser() -> ArgumentParser:
606
795
  formatter_class=RawTextHelpFormatter,
607
796
  epilog=textwrap.dedent(
608
797
  """
609
- Type 'python -m onnx_diagnostic <cmd> --help'
610
- to get help for a specific command.
611
-
612
- config - prints a configuration for a model id
613
- find - find node consuming or producing a result
614
- lighten - makes an onnx model lighter by removing the weights,
615
- unlighten - restores an onnx model produces by the previous experiment
616
- print - prints the model on standard output
617
- validate - validate a model
618
- stats - produces statistics on a model
619
- """
798
+ Type 'python -m onnx_diagnostic <cmd> --help'
799
+ to get help for a specific command.
800
+
801
+ agg - aggregates statistics from multiple files
802
+ config - prints a configuration for a model id
803
+ find - find node consuming or producing a result
804
+ lighten - makes an onnx model lighter by removing the weights,
805
+ print - prints the model on standard output
806
+ stats - produces statistics on a model
807
+ unlighten - restores an onnx model produces by the previous experiment
808
+ validate - validate a model
809
+ """
620
810
  ),
621
811
  )
622
812
  parser.add_argument(
623
813
  "cmd",
624
- choices=["config", "find", "lighten", "print", "stats", "unlighten", "validate"],
814
+ choices=[
815
+ "agg",
816
+ "config",
817
+ "find",
818
+ "lighten",
819
+ "print",
820
+ "stats",
821
+ "unlighten",
822
+ "validate",
823
+ ],
625
824
  help="Selects a command.",
626
825
  )
627
826
  return parser
@@ -636,6 +835,7 @@ def main(argv: Optional[List[Any]] = None):
636
835
  config=_cmd_config,
637
836
  validate=_cmd_validate,
638
837
  stats=_cmd_stats,
838
+ agg=_cmd_agg,
639
839
  )
640
840
 
641
841
  if argv is None:
@@ -657,6 +857,7 @@ def main(argv: Optional[List[Any]] = None):
657
857
  config=get_parser_config,
658
858
  validate=get_parser_validate,
659
859
  stats=get_parser_stats,
860
+ agg=get_parser_agg,
660
861
  )
661
862
  cmd = argv[0]
662
863
  if cmd not in parsers:
onnx_diagnostic/doc.py CHANGED
@@ -2,6 +2,28 @@ from typing import Optional
2
2
  import numpy as np
3
3
 
4
4
 
5
+ def get_latest_pypi_version(package_name="onnx-diagnostic") -> str:
6
+ """Returns the latest published version."""
7
+
8
+ import requests
9
+
10
+ url = f"https://pypi.org/pypi/{package_name}/json"
11
+ response = requests.get(url)
12
+
13
+ assert response.status_code == 200, f"Unable to retrieve the version response={response}"
14
+ data = response.json()
15
+ version = data["info"]["version"]
16
+ return version
17
+
18
+
19
+ def update_version_package(version: str, package_name="onnx-diagnostic") -> str:
20
+ "Adds dev if the major version is different from the latest published one."
21
+ released = get_latest_pypi_version(package_name)
22
+ shorten_r = ".".join(released.split(".")[:2])
23
+ shorten_v = ".".join(version.split(".")[:2])
24
+ return version if shorten_r == shorten_v else f"{shorten_v}.dev"
25
+
26
+
5
27
  def reset_torch_transformers(gallery_conf, fname):
6
28
  "Resets torch dynamo for :epkg:`sphinx-gallery`."
7
29
  import matplotlib.pyplot as plt