跳至主要内容

ONNXRuntime Transformer模型优化工具

项目描述

Transformer模型优化工具概述

ONNX Runtime在加载transformer模型时自动应用大多数优化。一些尚未集成到ONNX Runtime的最新优化可以在该工具中找到,以获得最佳性能。

该工具可以帮助以下场景:

  • 模型由tf2onnx或keras2onnx导出,而ONNX Runtime目前没有针对它们的图优化。
  • 将模型转换为使用float16以在具有Tensor Cores的GPU(如V100或T4)上使用混合精度来提升性能。
  • 模型有具有动态轴的输入,这由于形状推断而阻止了ONNX Runtime应用某些优化。
  • 禁用或启用某些融合以查看其对性能或准确性的影响。

安装

首先您需要安装用于CPU或GPU推理的onnxruntime或onnxruntime-gpu包。要使用onnxruntime-gpu,需要安装CUDA和cuDNN,并将它们的bin目录添加到PATH环境变量中。

限制

由于Attention内核的CUDA实现,最大注意力头数为1024。通常,Longformer的最大支持序列长度为4096,其他类型模型为1024。

将Transformer模型导出到ONNX

PyTorch 可以将模型导出为 ONNX 格式。tf2onnx 和 keras2onnx 工具可以用于将 TensorFlow 训练的模型转换为 ONNX 格式。Huggingface Transformers 有一个 笔记本 展示了将预训练模型导出到 ONNX 的示例。对于 Keras2onnx,请参阅其 示例脚本。对于 tf2onnx,请参阅其 BERT 教程

GPT-2 模型转换

当使用过去状态时,将 PyTorch 的 GPT-2 模型转换为 ONNX 并不简单。我们添加了一个 convert_to_onnx 工具来帮助您。

您可以使用以下命令将预训练的 PyTorch GPT-2 模型转换为 ONNX,适用于给定的精度(float32、float16 或 int8)

python -m onnxruntime.transformers.convert_to_onnx -m gpt2 --model_class GPT2LMHeadModel --output gpt2.onnx -p fp32
python -m onnxruntime.transformers.convert_to_onnx -m distilgpt2 --model_class GPT2LMHeadModel --output distilgpt2.onnx -p fp16 --use_gpu --optimize_onnx
python -m onnxruntime.transformers.convert_to_onnx -m [path_to_gpt2_pytorch_model_directory] --output quantized.onnx -p int32 --optimize_onnx

此工具还将验证当使用相同的随机输入时,ONNX 模型和相应的 PyTorch 模型是否生成相同的输出。

Longformer 模型转换

要求:Linux 操作系统(例如 Ubuntu 18.04 或 20.04)以及以下类似的 Python 环境

conda create -n longformer python=3.6
conda activate longformer
conda install pytorch torchvision torchaudio cpuonly -c pytorch
pip install onnx transformers onnxruntime

接下来,获取 Longformer 导出所需的 torch 扩展 的源代码,并运行以下命令

python setup.py install

它将在目录下生成类似 "build/lib.linux-x86_64-3.6/longformer_attention.cpython-36m-x86_64-linux-gnu.so" 的文件。

最后,使用 convert_longformer_to_onnx 将模型转换为以下 ONNX 模型

python convert_longformer_to_onnx.py -m longformer-base-4096

目前导出的 ONNX 模型只能在 GPU 上运行。

模型优化器

在您的 Python 代码中,您可以使用以下优化器

from onnxruntime.transformers import optimizer
optimized_model = optimizer.optimize_model("gpt2.onnx", model_type='gpt2', num_heads=12, hidden_size=768)
optimized_model.convert_model_float32_to_float16()
optimized_model.save_model_to_file("gpt2_fp16.onnx")

您也可以使用命令行。以下是将 BERT-large 模型优化为使用混合精度(float16)的示例

python -m onnxruntime.transformers.optimizer --input bert_large.onnx --output bert_large_fp16.onnx --num_heads 16 --hidden_size 1024 --float16

您也可以从 此处 下载最新的脚本文件。然后按照以下方式运行

python optimizer.py --input gpt2.onnx --output gpt2_opt.onnx --model_type gpt2

优化器选项

以下是对 optimizer.py 中一些选项的描述

  • input:输入模型路径
  • output:输出模型路径
  • model_type:(默认:bert) 有 4 种模型类型:bert(由 PyTorch 导出)、gpt2(由 PyTorch 导出)、bert_tf(由 tf2onnx 导出的 BERT)和 bert_keras(由 keras2onnx 导出的 BERT)。
  • num_heads:(默认:12) 注意力头数。BERT-base 和 BERT-large 分别有 12 和 16 个。
  • hidden_size:(默认:768) BERT-base 和 BERT-large 分别有 768 和 1024 个隐藏节点。
  • input_int32:(可选) 通常导出的模型使用 int64 张量作为输入。如果指定此标志,则使用 int32 张量作为输入,并且可以避免不必要的 Cast 节点并获得更好的性能。
  • float16:(可选) 默认情况下,模型使用 float32 进行计算。如果指定此标志,则使用半精度浮点数。此选项建议用于具有 Tensor Core 的 NVidia GPU,例如 V100 和 T4。对于较旧的 GPU,float32 可能更快。
  • use_gpu:(可选) 当 opt_level > 1 时,请为此标志设置 GPU 推理。
  • opt_level:(可选) 设置 OnnxRuntime 的适当图优化级别:0 - 禁用所有(默认),1 - 基本优化,2 - 扩展优化,99 - 所有优化。如果值为正,OnnxRuntime 首先用于优化图。
  • verbose:(可选) 当指定此标志时,打印详细信息。

支持的模式

以下是在使用优化器测试过的来自 Huggingface Transformers 的 PyTorch 模型列表

  • BERT
  • DistilBERT
  • DistilGPT2
  • RoBERTa
  • ALBERT
  • GPT-2 (模型, LMHead模型)

对于Tensorflow模型,目前我们只测试了BERT模型。

大多数优化都需要子图的精确匹配。子图中的任何布局更改都可能导致某些优化不起作用。请注意,不同版本的训练或导出工具可能会导致不同的图布局。建议使用PyTorch和Transformers的最新发布版本。

如果你的模型不在列表中,它可能只部分优化或根本没有优化。

基准测试

有一个用于运行基准测试的bash脚本run_benchmark.sh。在运行之前,你可以修改bash脚本来选择你的选项(如要测试的模型、批大小、序列长度、目标设备等)。

该bash脚本将调用benchmark.py脚本来测量OnnxRuntime、PyTorch或PyTorch+TorchScript在Huggingface Transformers预训练模型上的推理性能。

V100上的基准测试结果

在以下基准测试结果中,ONNX Runtime使用优化器进行模型优化,并且启用了IO绑定。

我们在Tesla V100-PCIE-16GB GPU(CPU是Intel Xeon(R) E5-2690 v4)上测试了不同的批大小(b)和序列长度(s)。以下结果为每次推理的平均延迟(毫秒)。

bert-base-uncased (BertModel)

该模型有12层和768个隐藏层,以input_ids作为输入。

引擎 版本 精度 b s=8 s=16 s=32 s=64 s=128 s=256 s=512
torchscript 1.5.1 fp32 1 7.92 8.78 8.91 9.18 9.56 9.39 12.83
onnxruntime 1.4.0 fp32 1 1.38 1.42 1.67 2.15 3.11 5.37 10.74
onnxruntime 1.4.0 fp16 1 1.30 1.29 1.31 1.33 1.45 1.95 3.36
onnxruntime 1.4.0 fp32 4 1.51 1.93 2.98 5.01 9.13 17.95 38.15
onnxruntime 1.4.0 fp16 4 1.27 1.35 1.43 1.83 2.66 4.40 9.76

run_benchmark.sh用于获取结果。

gpt2 (GPT2LMHeadModel)

该模型有12层和768个隐藏层,以input_ids、position_ids、attention_mask和过去状态作为输入。

引擎 版本 精度 b s=4 s=8 s=32 s=128
torchscript 1.5.1 fp32 1 5.80 5.77 5.82 5.78
onnxruntime 1.4.0 fp32 1 1.42 1.42 1.43 1.47
onnxruntime 1.4.0 fp16 1 1.54 1.54 1.58 1.64
onnxruntime 1.4.0 fp32 8 1.83 1.84 1.90 2.13
onnxruntime 1.4.0 fp16 8 1.74 1.75 1.81 2.09
onnxruntime 1.4.0 fp32 32 2.19 2.21 2.45 3.34
onnxruntime 1.4.0 fp16 32 1.66 1.71 1.85 2.73
onnxruntime 1.4.0 fp32 128 4.15 4.37 5.15 8.61
onnxruntime 1.4.0 fp16 128 2.47 2.58 3.26 6.16

由于使用了过去状态,input_ids中的序列长度为1。例如,s=4表示过去序列长度为4,总序列长度为5。

benchmark_gpt2.py用于获取以下命令类似的结果

python -m onnxruntime.transformers.benchmark_gpt2 --use_gpu -m gpt2 -o -v -b 1 8 32 128 -s 4 8 32 128 -p fp32
python -m onnxruntime.transformers.benchmark_gpt2 --use_gpu -m gpt2 -o -v -b 1 8 32 128 -s 4 8 32 128 -p fp16

Benchmark.py

如果你使用run_benchmark.sh,你不需要直接使用benchmark.py。如果你不想了解详细信息,可以跳过此部分。

以下是在GPU上运行预训练模型bert-base-cased的benchmark.py的示例。

python -m onnxruntime.transformers.benchmark -g -m bert-base-cased -o -v -b 0
python -m onnxruntime.transformers.benchmark -g -m bert-base-cased -o
python -m onnxruntime.transformers.benchmark -g -m bert-base-cased -e torch
python -m onnxruntime.transformers.benchmark -g -m bert-base-cased -e torchscript

第一条命令将生成ONNX模型(优化前后),但由于批大小为0,不会运行性能测试。其他三个命令将对每个三个引擎(OnnxRuntime、PyTorch和PyTorch+TorchScript)运行性能测试。

如果你删除了-o参数,则不在基准测试中使用优化器脚本。

如果你的GPU(如V100或T4)具有TensorCore,你可以在上述命令后追加-p fp16以启用混合精度。

如果你想在CPU上基准测试,你可以在命令中删除-g选项。

请注意,我们目前对GPT2和DistilGPT2模型的基准测试已禁用输入和输出中的过去状态。

默认情况下,ONNX模型只有一个输入(input_ids)。你可以使用-i参数来测试具有多个输入的模型。例如,我们可以将"-i 3"添加到命令行来测试一个有3个输入(input_ids、token_type_ids和attention_mask)的bert模型。此选项目前仅支持OnnxRuntime。

BERT模型验证

如果你的BERT模型有三个输入(如input_ids、token_type_ids和attention_mask),可以使用compare_bert_results.py脚本来进行快速验证。该工具将生成一些伪造的输入数据,并比较原始和优化模型的输出结果。如果输出结果都很接近,则可以使用优化后的模型。

针对CPU优化的模型验证示例

python -m onnxruntime.transformers.compare_bert_results --baseline_model original_model.onnx --optimized_model optimized_model_cpu.onnx --batch_size 1 --sequence_length 128 --samples 100

对于GPU,请在命令中追加--use_gpu。

性能测试

可以使用bert_perf_test.py来检查BERT模型推理性能。以下是示例:

python -m onnxruntime.transformers.bert_perf_test --model optimized_model_cpu.onnx --batch_size 1 --sequence_length 128

对于GPU,请在命令中追加--use_gpu。

测试完成后,将在模型目录中输出类似于perf_results_CPU_B1_S128_<date_time>.txt或perf_results_GPU_B1_S128_<date_time>.txt的文件。

性能分析

可以使用profiler.py在Transformer模型上运行性能分析。它可以帮助找出模型的瓶颈以及节点或子图上花费的CPU时间。

示例命令

python -m onnxruntime.transformers.profiler --model bert.onnx --batch_size 8 --sequence_length 128 --samples 1000 --dummy_inputs bert --thread_num 8 --kernel_time_only
python -m onnxruntime.transformers.profiler --model gpt2.onnx --batch_size 1 --sequence_length 1 --past_sequence_length 128 --samples 1000 --dummy_inputs gpt2 --use_gpu
python -m onnxruntime.transformers.profiler --model longformer.onnx --batch_size 1 --sequence_length 4096 --global_length 8 --samples 1000 --dummy_inputs longformer --use_gpu

结果文件,如onnxruntime_profile__<date_time>.json,将被输出到当前目录。节点摘要、最昂贵的节点和按操作类型分组的结果的总结将被打印到控制台。

项目详情


下载文件

下载适合您平台文件的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码发行版

onnxruntime_tools-1.7.0.tar.gz (141.4 kB 查看哈希)

上传时间 源代码

构建发行版

onnxruntime_tools-1.7.0-py3-none-any.whl (212.7 kB 查看哈希)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页