ONNX开放神经网络交换
简要说明:
- 在计算机视觉中,通常使用TensorRT优化模型推断过程,尤其在NVIDIA GPU上,可以显著提高推断性能;在NLP领域,使用TensorRT并不是一个常见的做法,这是因为NLP模型的推断通常有CPU或者GPU完成,而不像CV那样直接利用TensorRT进行硬件加速,NLP模型的架构和需求也不同。
- NLP中,常见的部署方法包括将整个模型转换为ONNX格式,然后使用ONNX Runtime进行推断。
- NLP部署通常更注重模型的端到端流程、跨平台兼容性和易用性,而不像CV那样专注于硬件加速。
0 参考:
python >> onnx: zhuanlan.zhihu.com/p/498425043
[模型部署]:深度学习模型部署(已更Pytorch篇):blog.csdn.net/qq_41897558…
深度学习模型部署篇——从0部署深度学习分类模型(一):juejin.cn/post/726720…
netron 神经网络可视化教程:zhuanlan.zhihu.com/p/431445882
1 Python-ONNX-TensorRT:
-
训练阶段:
- 使用 PyTorch 框架在支持 NVIDIA GPU 的系统上进行训练,并使用 CUDA 来加速训练过程。
- 训练完成后,你可以选择将模型保存为 PyTorch 模型(包含 GPU 参数)。
-
推断阶段:
- 在推断阶段,可以加载训练好的 PyTorch 模型,并使用 CUDA 进行 GPU 加速的推断。这样可以充分利用 GPU 的并行计算能力,提高推断性能。
-
模型保存:
- 可以选择将训练好的模型以两种方式保存:
- 以 GPU 训练的方式保存:这样保存的模型将包含 GPU 参数。
- 以 CPU 训练的方式保存:这样保存的模型将只包含 CPU 参数。
- 可以选择将训练好的模型以两种方式保存:
-
转换为 ONNX 格式:
- 使用 PyTorch 的 torch.onnx.export
-
TensorRT 优化:
- 使用 NVIDIA TensorRT 将 ONNX 格式的模型转换为 TensorRT 格式。这一步骤会应用 TensorRT 的硬件优化技术,提高推断性能。
Key
- 将模型转换成onnx格式时,模型形式是GPU还是CPU的都行,不影响
- tensorrt只用于推理阶段,不用于训练阶段
- CUDA是invida提供的并行计算平台和编程模型,cuDNN时nvidia提供的深度学习库,深度学习框架调cuDNN来执行底层深度学习计算,cuDNN是CUDA的一部分,提供了深度学习所需的一些优化功能
- pytorch在训练阶段通常会充分利用动态图计算和自动微分的优势,TensorRT并没有针对这些训练框架做直接的支持,它可以进行精确度的降低,减少推断时的计算量,从而提高推断性能。
import torch
import onnx
import onnxruntime as ort
print('PyTorch 版本', torch.**version**)
print('ONNX 版本', onnx.**version**)
print("CUDA 是否能用? ", torch.cuda.is\_available())
print("GPU 型号: ", torch.cuda.get\_device\_name(0))
print("torch version: ", torch.**version**)
print("CUDA version:", torch.version.cuda)
print("cuDNN version:", torch.backends.cudnn.version())
2 python 转换为onnx示例:
- 其中model表示要转换的pytorch模型;x是模型的任意一组输入,注意这个输入的shape要和模型输入相匹
import torch
from transformers import BertTokenizer, BertForSequenceClassification
device = torch.device("cuda" if torch.cuda.is\_available() else "cpu")) # 加载预训练的 BERT 模型和分词器
model = BertForSequenceClassification.from\_pretrained('bert-base-uncased')
tokenizer = BertTokenizer.from\_pretrained('bert-base-uncased') # 输入文本
text = "Hello, how are you doing today?" # 使用分词器进行 tokenization,并转换为模型输入格式 inputs = tokenizer(text, return\_tensors='pt') # 导出 ONNX 模型
torch.onnx.export(
model, # PyTorch 模型
(inputs\['input\_ids'], inputs\['attention\_mask']), # 模型输入 "bert\_model.onnx", # 输出文件路径
verbose=True,
input\_names=\['input\_ids', 'attention\_mask'], # 模型输入名称 output\_names=\['output'], # 模型输出名称
dynamic\_axes={'input\_ids': {0: 'batch\_size'}, 'attention\_mask': {0: 'batch\_size'}, 'output': {0: 'batch\_size'}}, # 动态轴
)
3 torch.onnx.export()参数详解:
torch.onnx.export(
model, # 要导出的 PyTorch 模型
args, # 模型输入参数,可以是单个 Tensor 或包含多个 Tensor 的元组或列表
f, # 导出的 ONNX 文件路径或文件对象
export\_params=True, # 是否导出模型的权重参数
verbose=False, # 是否输出详细信息
training=False, # 是否导出为训练模式
input\_names=None, # 模型输入的名称,可以是字符串或包含多个字符串的列表
output\_names=None, # 模型输出的名称,可以是字符串或包含多个字符串的列表
aten=False, # 是否使用 ATen 运算符,如果为 False,则使用标准 ONNX 运算符
export\_raw\_ir=False, # 是否导出未优化的中间表示
operator\_export\_type=None, # 导出运算符的类型,可以是 OperatorExportTypes 枚举的值
opset\_version=None, # 使用的 ONNX Opset 版本号
do\_constant\_folding=True, # 是否对模型进行常量折叠优化
dynamic\_axes=None, # 动态轴的字典,用于指定哪些维度是动态的
example\_outputs=None, # 示例输出,用于确定导出的模型的形状
keep\_initializers\_as\_inputs=None
) # 是否将模型的初始化器作为输入
4 Netron可视化:
!pip install netron
!netron path/to/your/bert\_model.onnx
- 可以发现图中没有特征图的维度,只有输入数据的维度
- 在netron中,如果想看到特征图的维度,需要在导出为onnx的时候,同时加上特征图维度信息。
# 增加维度信息
model\_file = 'model.onnx'
onnx\_model = onnx.load(model\_file) onnx.save(onnx.shape\_inference.infer\_shapes(onnx\_model), model\_file)
5 train()模式和eval()模式:
- pytorch中,模型有两种模式,训练模式(model.train())和评估模式(model.eval())。两种模式主要影响到一些特定的层:Batch Normalization 和 Dropout
- 在训练模式下,BN会使用当前batch的均值和方差进行归一化,而评估模式下,BN会使用整个训练集的均值和方差进行归一化,Dropout也不会执行随机丢弃
- 在模型导出到ONNX格式时,最好将模式转换为评估模式,可以避免由于训练模式下的特殊操作而导致的不一致性
6 ONNX Runtime & TensorRT 推理引擎:
-
支持的框架和模型格式:
- ONNX Runtime 是一个开放式的深度学习推理引擎,它可以支持多种深度学习框架(如PyTorch、TensorFlow、MXNet等)导出的 ONNX 模型。
- TensorRT 是 NVIDIA 推出的用于深度学习推理的库,主要支持 NVIDIA GPU。它可以直接优化 TensorFlow 或 PyTorch 模型,并且也能够从 ONNX 模型进行转换。
-
平台支持:
- ONNX Runtime 具有较好的跨平台支持,可以在多种硬件平台上运行,包括 CPU、GPU 和边缘设备。
- TensorRT 主要针对 NVIDIA GPU 进行了优化,因此在 NVIDIA GPU 上表现更为出色。
-
部署和集成:
- ONNX Runtime 更灵活,因为它是一个通用的深度学习推理引擎,适用于多种硬件和场景。
- TensorRT 专注于 NVIDIA GPU 上的优化,适用于需要充分利用 NVIDIA GPU 性能的场景。
-
性能和优化:
- TensorRT 在 NVIDIA GPU 上进行了更深入的优化,通常在这个硬件平台上表现更优。
- ONNX Runtime 也有一些优化策略,但可能不如 TensorRT 针对 NVIDIA GPU 那么深入。
-
部署环境:
- ONNX Runtime 更适合跨平台和多硬件环境的部署,因此可以更灵活地应用于不同的场景。
- TensorRT 更适合专注于 NVIDIA GPU 的部署,特别是在需要充分利用 GPU 性能的场合。
import onnxruntime
ort\_session = onnxruntime.InferenceSession('bert\_model.onnx')
# ONNX Runtime 输入
ort\_inputs = {'input': input\_tensor}
# ONNX Runtime 输出
pred\_logits = ort\_session.run(\['output'], ort\_inputs)\[0]
pred\_logits = torch.tensor(pred\_logits)
""" 这里我们把input\_tensor先构建成一个字典,该字典的键input要和
torch.onnx.export函数中输入名称一 致。 ort\_session.run方法
的参数有两个,第一个是输出张量名称,也就是output,这个也和我们前面
torch.onnx.export函数中输出名称一致。 """