Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
benchmark.py946 linesDownload Raw Back to transformers
1# Copyright (c) Microsoft Corporation.  All rights reserved.
2# Copyright 2018 The HuggingFace Inc. team.
3# Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""Benchmarking the inference of pretrained transformer models.
17PyTorch/TorchScript benchmark is based on https://github.com/huggingface/transformers/blob/master/examples/benchmarks.py.
18One difference is that random input_ids is generated in this benchmark.
19
20For onnxruntime, this script will convert a pretrained model to ONNX, and optimize it when -o parameter is used.
21
22Example commands:
23    Export all models to ONNX, optimize and validate them:
24        python benchmark.py -b 0 -o -v -i 1 2 3
25    Run OnnxRuntime on GPU for all models:
26        python benchmark.py -g
27    Run OnnxRuntime on GPU for all models with fp32 optimization:
28        python benchmark.py -g -o
29    Run OnnxRuntime on GPU with fp16 optimization:
30        python benchmark.py -g -o -p "fp16"
31    Run TorchScript on GPU for all models:
32        python benchmark.py -e torchscript -g
33    Run TorchScript on GPU for all models with fp16:
34        python benchmark.py -e torchscript -g -p "fp16"
35    Run ONNXRuntime and TorchScript on CPU for all models with quantization:
36        python benchmark.py -e torchscript onnxruntime -p "int8" -o
37    Run OnnxRuntime with bfloat16 fastmath mode kernels on aarch64 platforms with bfloat16 support:
38        python benchmark.py --enable_arm64_bfloat16_fastmath_mlas_gemm
39
40It is recommended to use run_benchmark.sh to launch benchmark.
41"""
42
43import argparse
44import logging
45import os
46import random
47import timeit
48from datetime import datetime
49
50import numpy
51import psutil
52from benchmark_helper import (
53    ConfigModifier,
54    OptimizerInfo,
55    Precision,
56    create_onnxruntime_session,
57    get_latency_result,
58    inference_ort,
59    inference_ort_with_io_binding,
60    output_details,
61    output_fusion_statistics,
62    output_summary,
63    setup_logger,
64)
65from fusion_options import FusionOptions
66from huggingface_models import MODEL_CLASSES, MODELS
67from onnx_exporter import (
68    create_onnxruntime_input,
69    export_onnx_model_from_pt,
70    export_onnx_model_from_tf,
71    load_pretrained_model,
72)
73from packaging import version
74from quantize_helper import QuantizeHelper
75
76logger = logging.getLogger("")
77
78cpu_count = psutil.cpu_count(logical=False)
79
80# Set OMP environment variable before importing onnxruntime or torch.
81if "OMP_NUM_THREADS" not in os.environ:
82    os.environ["OMP_NUM_THREADS"] = str(cpu_count)
83
84import torch  # noqa: E402
85from transformers import AutoConfig, AutoTokenizer, LxmertConfig  # noqa: E402
86
87
88def run_onnxruntime(
89    use_gpu,
90    provider,
91    model_names,
92    model_class,
93    config_modifier,
94    precision,
95    num_threads,
96    batch_sizes,
97    sequence_lengths,
98    repeat_times,
99    input_counts,
100    optimizer_info,
101    validate_onnx,
102    cache_dir,
103    onnx_dir,
104    verbose,
105    overwrite,
106    disable_ort_io_binding,
107    use_raw_attention_mask,
108    model_fusion_statistics,
109    model_source,
110    enable_arm64_bfloat16_fastmath_mlas_gemm,
111    args,
112):
113    import onnxruntime  # noqa: PLC0415
114
115    results = []
116    if (
117        use_gpu
118        and ("CUDAExecutionProvider" not in onnxruntime.get_available_providers())
119        and ("MIGraphXExecutionProvider" not in onnxruntime.get_available_providers())
120        and ("DmlExecutionProvider" not in onnxruntime.get_available_providers())
121    ):
122        logger.error(
123            "Please install onnxruntime-gpu or onnxruntime-directml package instead of onnxruntime, and use a machine with GPU for testing gpu performance."
124        )
125        return results
126
127    warm_up_repeat = 0
128    if provider == "tensorrt":
129        optimizer_info = OptimizerInfo.NOOPT
130        warm_up_repeat = 5
131        if "TensorrtExecutionProvider" not in onnxruntime.get_available_providers():
132            logger.error(
133                "Please install onnxruntime-gpu-tensorrt package, and use a machine with GPU for testing gpu performance."
134            )
135            return results
136
137    if optimizer_info == OptimizerInfo.NOOPT:
138        logger.warning(
139            f"OptimizerInfo is set to {optimizer_info}, graph optimizations specified in FusionOptions are not applied."
140        )
141
142    for model_name in model_names:
143        all_input_names = MODELS[model_name][0]
144        for num_inputs in input_counts:
145            if num_inputs > len(all_input_names):
146                break
147
148            input_names = all_input_names[:num_inputs]
149            args.model_type = MODELS[model_name][3]
150            fusion_options = FusionOptions.parse(args)
151
152            if "pt" in model_source:
153                with torch.no_grad():
154                    (
155                        onnx_model_file,
156                        is_valid_onnx_model,
157                        vocab_size,
158                        max_sequence_length,
159                    ) = export_onnx_model_from_pt(
160                        model_name,
161                        MODELS[model_name][1],
162                        MODELS[model_name][2],
163                        MODELS[model_name][3],
164                        model_class,
165                        config_modifier,
166                        cache_dir,
167                        onnx_dir,
168                        input_names,
169                        use_gpu,
170                        precision,
171                        optimizer_info,
172                        validate_onnx,
173                        use_raw_attention_mask,
174                        overwrite,
175                        model_fusion_statistics,
176                        fusion_options,
177                    )
178            if "tf" in model_source:
179                (
180                    onnx_model_file,
181                    is_valid_onnx_model,
182                    vocab_size,
183                    max_sequence_length,
184                ) = export_onnx_model_from_tf(
185                    model_name,
186                    MODELS[model_name][1],
187                    MODELS[model_name][2],
188                    MODELS[model_name][3],
189                    model_class,
190                    config_modifier,
191                    cache_dir,
192                    onnx_dir,
193                    input_names,
194                    use_gpu,
195                    precision,
196                    optimizer_info,
197                    validate_onnx,
198                    use_raw_attention_mask,
199                    overwrite,
200                    model_fusion_statistics,
201                    fusion_options,
202                )
203
204            if not is_valid_onnx_model:
205                continue
206
207            ort_session = create_onnxruntime_session(
208                onnx_model_file,
209                use_gpu,
210                provider,
211                enable_all_optimization=True,
212                num_threads=num_threads,
213                verbose=verbose,
214                enable_mlas_gemm_fastmath_arm64_bfloat16=enable_arm64_bfloat16_fastmath_mlas_gemm,
215            )
216            if ort_session is None:
217                continue
218
219            ort_output_names = [node_arg.name for node_arg in ort_session.get_outputs()]
220            output_buffers = []
221            device = "cuda" if use_gpu else "cpu"
222            config = AutoConfig.from_pretrained(model_name, cache_dir=cache_dir)
223            max_last_state_size = numpy.prod(
224                [
225                    max(batch_sizes),
226                    max(sequence_lengths),
227                    max(vocab_size, config.hidden_size),
228                ]
229            )
230            max_pooler_size = numpy.prod([max(batch_sizes), config.hidden_size])
231            for batch_size in batch_sizes:
232                if batch_size <= 0:
233                    continue
234                for sequence_length in sequence_lengths:
235                    if max_sequence_length is not None and sequence_length > max_sequence_length:
236                        continue
237
238                    input_value_type = numpy.int64 if "pt" in model_source else numpy.int32
239                    ort_inputs = create_onnxruntime_input(
240                        vocab_size,
241                        batch_size,
242                        sequence_length,
243                        input_names,
244                        config,
245                        input_value_type,
246                    )
247                    result_template = {
248                        "engine": "onnxruntime",
249                        "version": onnxruntime.__version__,
250                        "providers": provider,
251                        "device": device,
252                        "optimizer": optimizer_info,
253                        "precision": precision,
254                        "io_binding": not disable_ort_io_binding,
255                        "model_name": model_name,
256                        "inputs": num_inputs,
257                        "threads": num_threads,
258                        "batch_size": batch_size,
259                        "sequence_length": sequence_length,
260                        "custom_layer_num": config_modifier.get_layer_num(),
261                        "datetime": str(datetime.now()),
262                    }
263
264                    if config.model_type in ["vit", "swin"]:
265                        logger.info(
266                            f"Run onnxruntime on {model_name} with input shape {[batch_size, 3, config.image_size, config.image_size]}"
267                        )
268                    else:
269                        logger.info(f"Run onnxruntime on {model_name} with input shape {[batch_size, sequence_length]}")
270
271                    if disable_ort_io_binding:
272                        result = inference_ort(
273                            ort_session,
274                            ort_inputs,
275                            result_template,
276                            repeat_times,
277                            batch_size,
278                            warm_up_repeat,
279                        )
280                    else:
281                        # Get output sizes from a dummy ort run
282                        ort_outputs = ort_session.run(ort_output_names, ort_inputs)
283                        output_buffer_max_sizes = [max_last_state_size]
284                        for i in range(len(ort_outputs)):
285                            if i == 2 and MODELS[model_name][3] == "gpt":
286                                # past state output max size
287                                output_buffer_max_sizes.append(max_pooler_size)
288                            else:
289                                output_buffer_max_sizes.append(max_last_state_size)
290
291                        data_type = numpy.longlong if "pt" in model_source else numpy.intc
292                        result = inference_ort_with_io_binding(
293                            ort_session,
294                            ort_inputs,
295                            result_template,
296                            repeat_times,
297                            ort_output_names,
298                            ort_outputs,
299                            output_buffers,
300                            output_buffer_max_sizes,
301                            batch_size,
302                            device,
303                            data_type,
304                            warm_up_repeat,
305                        )
306                    logger.info(result)
307                    results.append(result)
308
309    return results
310
311
312def run_pytorch(
313    use_gpu,
314    model_names,
315    model_class,
316    config_modifier,
317    precision,
318    num_threads,
319    batch_sizes,
320    sequence_lengths,
321    repeat_times,
322    torchscript,
323    torch2,
324    cache_dir,
325    verbose,
326):
327    results = []
328    if use_gpu and not torch.cuda.is_available():
329        logger.error("Please install PyTorch with Cuda, and use a machine with GPU for testing gpu performance.")
330        return results
331
332    torch.set_grad_enabled(False)
333
334    for model_name in model_names:
335        config = AutoConfig.from_pretrained(model_name, torchscript=torchscript, cache_dir=cache_dir)
336        config_modifier.modify(config)
337        model = load_pretrained_model(
338            model_name,
339            config=config,
340            cache_dir=cache_dir,
341            custom_model_class=model_class,
342        )
343
344        if config.model_type in ["vit", "swin"]:
345            # These models don't use sequence lengths, so just pick the first sequence length so that the summary still works
346            sequence_lengths = [sequence_lengths[0]]
347        else:
348            tokenizer = AutoTokenizer.from_pretrained(model_name, cache_dir=cache_dir)
349
350            max_input_size = tokenizer.model_max_length
351
352        logger.debug(f"Model {model}")
353        logger.debug(f"Number of parameters {model.num_parameters()}")
354
355        if precision == Precision.FLOAT16:
356            model.half()
357
358        device = torch.device("cuda:0" if use_gpu else "cpu")
359        model.to(device)
360
361        if precision == Precision.INT8:
362            model = QuantizeHelper.quantize_torch_model(model)
363
364        for batch_size in batch_sizes:
365            if batch_size <= 0:
366                continue
367
368            for sequence_length in sequence_lengths:
369                if config.model_type in ["vit", "swin"]:
370                    logger.info(
371                        f"Run PyTorch on {model_name} with input shape {[batch_size, 3, config.image_size, config.image_size]}"
372                    )
373                    input_ids = torch.randn(
374                        size=(batch_size, 3, config.image_size, config.image_size),
375                        dtype=torch.float16 if precision == Precision.FLOAT16 else torch.float32,
376                        device=device,
377                    )
378                else:
379                    if max_input_size is not None and sequence_length > max_input_size:
380                        continue
381
382                    logger.info(f"Run PyTorch on {model_name} with input shape {[batch_size, sequence_length]}")
383                    input_ids = torch.randint(
384                        low=0,
385                        high=config.vocab_size - 1,
386                        size=(batch_size, sequence_length),
387                        dtype=torch.long,
388                        device=device,
389                    )
390                try:
391                    inference = (
392                        torch.jit.trace(model, input_ids) if torchscript else torch.compile(model) if torch2 else model
393                    )
394                    inference(input_ids)
395
396                    runtimes = timeit.repeat(lambda: inference(input_ids), repeat=repeat_times, number=1)  # noqa: B023
397
398                    result = {
399                        "engine": "torchscript" if torchscript else "torch2" if torch2 else "torch",
400                        "version": torch.__version__,
401                        "providers": "NA",
402                        "device": "cuda" if use_gpu else "cpu",
403                        "optimizer": "",
404                        "precision": precision,
405                        "io_binding": "",
406                        "model_name": model_name,
407                        "inputs": 1,
408                        "threads": num_threads,
409                        "batch_size": batch_size,
410                        "sequence_length": sequence_length,
411                        "custom_layer_num": config_modifier.get_layer_num(),
412                        "datetime": str(datetime.now()),
413                    }
414                    result.update(get_latency_result(runtimes, batch_size))
415                    logger.info(result)
416                    results.append(result)
417                except RuntimeError as e:
418                    logger.exception(e)
419                    torch.cuda.empty_cache()
420
421    return results
422
423
424def run_with_tf_optimizations(do_eager_mode: bool, use_xla: bool):
425    from functools import wraps  # noqa: PLC0415
426
427    import tensorflow as tf  # noqa: PLC0415
428
429    def run_func(func):
430        @wraps(func)
431        def run_in_eager_mode(*args, **kwargs):
432            return func(*args, **kwargs)
433
434        @wraps(func)
435        @tf.function(jit_compile=use_xla)
436        def run_in_graph_mode(*args, **kwargs):
437            return func(*args, **kwargs)
438
439        if do_eager_mode is True:
440            assert use_xla is False, (
441                "Cannot run model in XLA, if `args.eager_mode` is set to `True`. Please set `args.eager_mode=False`."
442            )
443            return run_in_eager_mode
444        else:
445            return run_in_graph_mode
446
447    return run_func
448
449
450def run_tensorflow(
451    use_gpu,
452    model_names,
453    model_class,
454    config_modifier,
455    precision,
456    num_threads,
457    batch_sizes,
458    sequence_lengths,
459    repeat_times,
460    cache_dir,
461    verbose,
462):
463    results = []
464
465    import tensorflow as tf  # noqa: PLC0415
466
467    tf.config.threading.set_intra_op_parallelism_threads(num_threads)
468
469    if not use_gpu:
470        tf.config.set_visible_devices([], "GPU")
471
472    if use_gpu and not tf.test.is_built_with_cuda():
473        logger.error("Please install Tensorflow-gpu, and use a machine with GPU for testing gpu performance.")
474        return results
475
476    if use_gpu:  # Restrict TensorFlow to only use the first GPU
477        physical_devices = tf.config.list_physical_devices("GPU")
478        try:
479            tf.config.set_visible_devices(physical_devices[0], "GPU")
480            tf.config.experimental.set_memory_growth(physical_devices[0], True)
481            tf.distribute.OneDeviceStrategy(device="/gpu:0")
482        except RuntimeError as e:
483            logger.exception(e)
484
485    if precision == Precision.FLOAT16 or precision == Precision.INT8:
486        raise NotImplementedError("Mixed precision is currently not supported.")
487
488    for model_name in model_names:
489        config = AutoConfig.from_pretrained(model_name, cache_dir=cache_dir)
490        config_modifier.modify(config)
491
492        model = load_pretrained_model(
493            model_name,
494            config=config,
495            cache_dir=cache_dir,
496            custom_model_class=model_class,
497            is_tf_model=True,
498        )
499
500        tokenizer = AutoTokenizer.from_pretrained(model_name, cache_dir=cache_dir)
501
502        max_input_size = tokenizer.model_max_length
503
504        # Define tf.function-decorated forward functions once per model, outside the
505        # batch_size/sequence_length loops. Passing input_ids as an argument (instead
506        # of closing over it) allows tf.function to cache traced graphs by input shape
507        # rather than retracing on every loop iteration. See issue #14953.
508        @run_with_tf_optimizations(do_eager_mode=False, use_xla=False)
509        def encoder_forward(input_ids):
510            return model(input_ids, training=False)  # noqa: B023
511
512        @run_with_tf_optimizations(do_eager_mode=False, use_xla=False)
513        def encoder_decoder_forward(input_ids):
514            return model(input_ids, decoder_input_ids=input_ids, training=False)  # noqa: B023
515
516        @run_with_tf_optimizations(do_eager_mode=False, use_xla=False)
517        def lxmert_forward(input_ids):
518            feats = tf.random.normal([1, 1, config.visual_feat_dim])  # noqa: B023
519            pos = tf.random.normal([1, 1, config.visual_pos_dim])  # noqa: B023
520            return model(  # noqa: B023
521                input_ids,
522                visual_feats=feats,
523                visual_pos=pos,
524                training=False,
525            )
526
527        if config.is_encoder_decoder:
528            inference = encoder_decoder_forward
529        elif isinstance(config, LxmertConfig):
530            inference = lxmert_forward
531        else:
532            inference = encoder_forward
533
534        for batch_size in batch_sizes:
535            if batch_size <= 0:
536                continue
537
538            for sequence_length in sequence_lengths:
539                if max_input_size is not None and sequence_length > max_input_size:
540                    continue
541
542                logger.info(f"Run Tensorflow on {model_name} with input shape {[batch_size, sequence_length]}")
543
544                rng = random.Random()
545                values = [rng.randint(0, config.vocab_size - 1) for i in range(batch_size * sequence_length)]
546                input_ids = tf.constant(values, shape=(batch_size, sequence_length), dtype=tf.int32)
547
548                try:
549                    inference(input_ids)
550
551                    runtimes = timeit.repeat(lambda: inference(input_ids), repeat=repeat_times, number=1)  # noqa: B023
552
553                    result = {
554                        "engine": "tensorflow",
555                        "version": tf.__version__,
556                        "providers": "NA",
557                        "device": "cuda" if use_gpu else "cpu",
558                        "optimizer": "",
559                        "precision": precision,
560                        "io_binding": "",
561                        "model_name": model_name,
562                        "inputs": 1,
563                        "threads": num_threads,
564                        "batch_size": batch_size,
565                        "sequence_length": sequence_length,
566                        "custom_layer_num": config_modifier.get_layer_num(),
567                        "datetime": str(datetime.now()),
568                    }
569                    result.update(get_latency_result(runtimes, batch_size))
570                    logger.info(result)
571                    results.append(result)
572                except RuntimeError as e:
573                    logger.exception(e)
574                    from numba import cuda  # noqa: PLC0415
575
576                    device = cuda.get_current_device()
577                    device.reset()
578
579    return results
580
581
582def parse_arguments():
583    parser = argparse.ArgumentParser()
584
585    parser.add_argument(
586        "-m",
587        "--models",
588        required=False,
589        nargs="+",
590        type=str,
591        default=["bert-base-cased", "roberta-base", "gpt2"],
592        choices=list(MODELS.keys()),
593        help="Pre-trained models in the list: " + ", ".join(MODELS.keys()),
594    )
595
596    parser.add_argument(
597        "--model_source",
598        required=False,
599        nargs=1,
600        type=str,
601        default="pt",
602        choices=["pt", "tf"],
603        help="Export onnx from pt or tf",
604    )
605
606    parser.add_argument(
607        "--model_class",
608        required=False,
609        type=str,
610        default=None,
611        choices=list(MODEL_CLASSES),
612        help="Model type selected in the list: " + ", ".join(MODEL_CLASSES),
613    )
614
615    parser.add_argument(
616        "-e",
617        "--engines",
618        required=False,
619        nargs="+",
620        type=str,
621        default=["onnxruntime"],
622        choices=["onnxruntime", "torch", "torch2", "torchscript", "tensorflow"],
623        help="Engines to benchmark",
624    )
625
626    parser.add_argument(
627        "-c",
628        "--cache_dir",
629        required=False,
630        type=str,
631        default=os.path.join(".", "cache_models"),
632        help="Directory to cache pre-trained models",
633    )
634
635    parser.add_argument(
636        "--onnx_dir",
637        required=False,
638        type=str,
639        default=os.path.join(".", "onnx_models"),
640        help="Directory to store onnx models",
641    )
642
643    parser.add_argument("-g", "--use_gpu", required=False, action="store_true", help="Run on gpu device")
644
645    parser.add_argument(
646        "--provider",
647        required=False,
648        type=str,
649        default=None,
650        help="Execution provider to use",
651    )
652
653    parser.add_argument(
654        "-p",
655        "--precision",
656        type=Precision,
657        default=Precision.FLOAT32,
658        choices=list(Precision),
659        help="Precision of model to run. fp32 for full precision, fp16 for half precision, and int8 for quantization",
660    )
661
662    parser.add_argument("--verbose", required=False, action="store_true", help="Print more information")
663
664    parser.add_argument(
665        "--overwrite",
666        required=False,
667        action="store_true",
668        help="Overwrite existing models",
669    )
670
671    parser.add_argument(
672        "-o",
673        "--optimizer_info",
674        type=OptimizerInfo,
675        default=OptimizerInfo.BYSCRIPT,
676        choices=list(OptimizerInfo),
677        help="Optimizer info: Use optimizer.py to optimize onnx model as default. Can also choose from by_ort and no_opt",
678    )
679
680    parser.add_argument(
681        "-v",
682        "--validate_onnx",
683        required=False,
684        action="store_true",
685        help="Validate ONNX model",
686    )
687
688    parser.add_argument(
689        "-f",
690        "--fusion_csv",
691        required=False,
692        default=None,
693        help="CSV file for saving summary results of graph optimization.",
694    )
695
696    parser.add_argument(
697        "-d",
698        "--detail_csv",
699        required=False,
700        default=None,
701        help="CSV file for saving detail results.",
702    )
703
704    parser.add_argument(
705        "-r",
706        "--result_csv",
707        required=False,
708        default=None,
709        help="CSV file for saving summary results.",
710    )
711
712    parser.add_argument(
713        "-i",
714        "--input_counts",
715        required=False,
716        nargs="+",
717        default=[1],
718        type=int,
719        choices=[1, 2, 3],
720        help="Number of ONNX model inputs. Please use 1 for fair comparison with Torch or TorchScript.",
721    )
722
723    parser.add_argument(
724        "-t",
725        "--test_times",
726        required=False,
727        default=100,
728        type=int,
729        help="Number of repeat times to get average inference latency.",
730    )
731
732    parser.add_argument("-b", "--batch_sizes", nargs="+", type=int, default=[1])
733
734    parser.add_argument(
735        "-s",
736        "--sequence_lengths",
737        nargs="+",
738        type=int,
739        default=[4, 8, 16, 32, 64, 128, 256],
740    )
741
742    parser.add_argument(
743        "--disable_ort_io_binding",
744        required=False,
745        action="store_true",
746        help="Disable running ONNX Runtime with binded inputs and outputs. ",
747    )
748    parser.set_defaults(disable_ort_io_binding=False)
749
750    parser.add_argument(
751        "-n",
752        "--num_threads",
753        required=False,
754        nargs="+",
755        type=int,
756        default=[0],
757        help="Threads to use",
758    )
759
760    parser.add_argument(
761        "--force_num_layers",
762        required=False,
763        type=int,
764        default=None,
765        help="Manually set the model's layer number",
766    )
767
768    parser.add_argument(
769        "--enable_arm64_bfloat16_fastmath_mlas_gemm",
770        required=False,
771        action="store_true",
772        help="Enable bfloat16 mlas gemm kernels on aarch64. Supported only for CPU EP ",
773    )
774    parser.set_defaults(enable_arm64_bfloat16_fastmath_mlas_gemm=False)
775
776    FusionOptions.add_arguments(parser)
777
778    args = parser.parse_args()
779    return args
780
781
782def main():
783    args = parse_arguments()
784
785    setup_logger(args.verbose)
786
787    if args.precision == Precision.FLOAT16 and not args.use_gpu:
788        logger.error("fp16 is for GPU only")
789        return
790
791    if args.precision == Precision.INT8 and args.use_gpu and args.provider not in ["migraphx"]:
792        logger.error("int8 is for CPU only")
793        return
794
795    if len(args.models) == 1 and MODELS[args.models[0]][3] in ["vit", "swim"]:
796        args.sequence_lengths = [""]
797
798    args.num_threads = sorted({cpu_count if x <= 0 else x for x in args.num_threads})
799
800    logger.info(f"Arguments: {args}")
801
802    if not os.path.exists(args.cache_dir):
803        try:
804            os.mkdir(args.cache_dir)
805        except OSError:
806            logger.error("Creation of the directory %s failed", args.cache_dir)
807
808    enable_torch = "torch" in args.engines
809    enable_torch2 = "torch2" in args.engines
810    enable_torchscript = "torchscript" in args.engines
811    enable_onnxruntime = "onnxruntime" in args.engines
812    enable_tensorflow = "tensorflow" in args.engines
813
814    if enable_torch2 and version.parse(torch.__version__) < version.parse("2.0.0"):
815        logger.error(f"PyTorch version must be >=2.0.0 and you are using {torch.__version__}")
816        return
817
818    config_modifier = ConfigModifier(args.force_num_layers)
819
820    results = []
821
822    for num_threads in args.num_threads:
823        torch.set_num_threads(num_threads)
824        logger.debug(torch.__config__.parallel_info())
825        if enable_torch or enable_torch2 or enable_torchscript:
826            if args.input_counts != [1]:
827                logger.warning("--input_counts is not implemented for torch or torchscript engine.")
828
829            if enable_torchscript:
830                results += run_pytorch(
831                    args.use_gpu,
832                    args.models,
833                    args.model_class,
834                    config_modifier,
835                    args.precision,
836                    num_threads,
837                    args.batch_sizes,
838                    args.sequence_lengths,
839                    args.test_times,
840                    True,
841                    False,
842                    args.cache_dir,
843                    args.verbose,
844                )
845
846            if enable_torch:
847                results += run_pytorch(
848                    args.use_gpu,
849                    args.models,
850                    args.model_class,
851                    config_modifier,
852                    args.precision,
853                    num_threads,
854                    args.batch_sizes,
855                    args.sequence_lengths,
856                    args.test_times,
857                    False,
858                    False,
859                    args.cache_dir,
860                    args.verbose,
861                )
862
863            if enable_torch2:
864                results += run_pytorch(
865                    args.use_gpu,
866                    args.models,
867                    args.model_class,
868                    config_modifier,
869                    args.precision,
870                    num_threads,
871                    args.batch_sizes,
872                    args.sequence_lengths,
873                    args.test_times,
874                    False,
875                    True,
876                    args.cache_dir,
877                    args.verbose,
878                )
879
880        if enable_tensorflow:
881            results += run_tensorflow(
882                args.use_gpu,
883                args.models,
884                args.model_class,
885                config_modifier,
886                args.precision,
887                num_threads,
888                args.batch_sizes,
889                args.sequence_lengths,
890                args.test_times,
891                args.cache_dir,
892                args.verbose,
893            )
894
895        model_fusion_statistics = {}
896        if enable_onnxruntime:
897            try:
898                use_raw_attention_mask = not args.use_mask_index
899                results += run_onnxruntime(
900                    args.use_gpu,
901                    args.provider,
902                    args.models,
903                    args.model_class,
904                    config_modifier,
905                    args.precision,
906                    num_threads,
907                    args.batch_sizes,
908                    args.sequence_lengths,
909                    args.test_times,
910                    args.input_counts,
911                    args.optimizer_info,
912                    args.validate_onnx,
913                    args.cache_dir,
914                    args.onnx_dir,
915                    args.verbose,
916                    args.overwrite,
917                    args.disable_ort_io_binding,
918                    use_raw_attention_mask,
919                    model_fusion_statistics,
920                    args.model_source,
921                    args.enable_arm64_bfloat16_fastmath_mlas_gemm,
922                    args,
923                )
924            except Exception:
925                logger.exception("Exception")
926
927    time_stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
928    if model_fusion_statistics:
929        csv_filename = args.fusion_csv or f"benchmark_fusion_{time_stamp}.csv"
930        output_fusion_statistics(model_fusion_statistics, csv_filename)
931
932    if len(results) == 0:
933        if args.batch_sizes != [0]:
934            logger.warning("No any result available.")
935        return
936
937    csv_filename = args.detail_csv or f"benchmark_detail_{time_stamp}.csv"
938    output_details(results, csv_filename)
939
940    csv_filename = args.result_csv or f"benchmark_summary_{time_stamp}.csv"
941    output_summary(results, csv_filename, args)
942
943
944if __name__ == "__main__":
945    main()
946 
codekingpro/portable-devtools · Team Ai