专栏名称: GiantPandaCV
专注于机器学习、深度学习、计算机视觉、图像处理等多个方向技术分享。团队由一群热爱技术且热衷于分享的小伙伴组成。我们坚持原创,每天一到两篇原创技术分享。希望在传播知识、分享知识的同时能够启发你,大家一起共同进步(・ω<)☆
目录
相关文章推荐
GiantPandaCV  ·  AwesomeCLIP---100+篇CLI ... ·  2 天前  
GiantPandaCV  ·  小白视角:利用 vllm serve 新的 ... ·  4 天前  
GiantPandaCV  ·  小白视角:利用 SGL 来 Serve ... ·  6 天前  
GiantPandaCV  ·  小白视角:vllm 迁移到 SGLang ... ·  1 周前  
51好读  ›  专栏  ›  GiantPandaCV

一文读懂 ONNX、TensorRT、OpenVINO部署框架

GiantPandaCV  · 公众号  · 3D  · 2024-09-25 18:40

正文

SmartFlowAI


点击上方蓝字关注我们

作者:企鹅火烈鸟🦩,北京邮电大学硕士

全文约 2700 字,预计阅读时间 7 分钟

大家好我是🐧小弟,🐦了巨久之后今天继续带来一期基础的深度学习模型部署的入门文章,随着上一期讲完 torch 的一些基础知识之后。这一期带大家来接触一些关于更加深入和规范化的部署相关的知识。

这一期主要会分几个点展开:为什么我们做部署的时候要在 torch 上更进一步使用 ONNX,TensorRT,OpenVINO 等部署框架,在做 cv 模型部署的时候。我们怎么部署。在做 LLM 部署的时候,我们又会怎么做呢?

动静转换:Torch上更进一步

Torch

虽说我们在上一节《部署知识库 | 基础知识:模型推理》讲了很多 torch 的好处和优点。最核心的就是 torch 使用了动态图组网。使用动态组网的好处是。可以使用更偏向 python 语法的格式对模型进行定义。下面就给大家一个常见的网络:

import torch
import torch.nn as nn
import torch.nn.functional as F

class SimpleNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, hidden_size)
        self.fc3 = nn.Linear(hidden_size, num_classes)
    
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 示例使用
input_size = 784  # 例如,对于MNIST数据集
hidden_size = 128
num_classes = 10

model = SimpleNet(input_size, hidden_size, num_classes)
print(model)

大家很容易开心的写出这样代码,但问题是,使用动态图模式。不可避免的带来了一系列问题。对于一个动态图来说,面临了以下三点问题:

  1. 性能

  • 动态图在每次执行时都需要重新构建计算图,这可能导致额外的开销。
  • 静态图只需构建一次,然后可以重复高效执行。
  • 优化难度

    • 动态图难以进行全局优化,因为图结构在运行时可能会改变。
    • 静态图允许更多的编译时优化,如内存分配优化、算子融合等。
  • 内存使用

    • 动态图可能需要更多的运行时内存,因为它需要保持 Python 解释器和相关对象的活跃状态。
    • 静态图可以更有效地管理内存,尤其是在推理阶段。

    所以从 torch 开始,我们第一步要做的就是动转静。拿到静态图才能更好的做整体性能上的优化!

    美好的愿景:ONNX

    ONNX,全称 Open Neural Network Exchange,是人工智能领域中一个引人入胜的故事。它的诞生源于一个美好的愿景:在纷繁复杂的深度学习世界中架起一座沟通的桥梁。

    2017 年的硅谷,各大科技巨头都在人工智能领域奋力拼搏。Facebook(现在的Meta)和 Microsoft 这两个看似竞争对手的公司,却因为一个共同的梦想走到了一起。他们希望打破AI框架之间的壁垒,让不同平台上训练的模型能够自由迁移。就这样,ONNX 项目应运而生。

    听起来 ONNX 是不同模型间完美的桥梁,最后聚合到 ONNX 完成推理是很开心和能接受的事情。但是听起来越完美的事情就面临越多的问题,首先是对 ONNX 来说。ONNX 模型在某些情况下可能比原生框架的模型运行得慢。这主要是因为 ONNX 作为一个中间表示,可能无法充分利用特定硬件或框架的优化特性。想象一下,它就像是一个通用翻译器,虽然能够让不同语言的人交流,但可能会损失一些语言中的微妙之处和效率。

    除此之外,AI 领域发展的太快。ONNX 并不一定能很好的表示 torch 中各种各样的算子,导致模型转换成 ONNX 失败。谈回之前简单的网络,我们如何把它转换成 ONNX 形式呢?请看:

    # 将模型转换为ONNX格式
    import torch.onnx

    # 创建一个示例输入张量
    dummy_input = torch.randn(1, input_size)

    # 指定ONNX文件的输出路径
    output_path = "simple_net.onnx"

    # 导出模型到ONNX
    torch.onnx.export(model,               # 要转换的模型
                      dummy_input,         # 模型的输入样例
                      output_path,         # 输出的ONNX文件路径
                      export_params=True,  # 存储训练好的参数权重
                      opset_version=11,    # ONNX算子集版本
                      do_constant_folding=True,  # 是否执行常量折叠优化
                      input_names=['input'],   # 输入节点的名称
                      output_names=['output'], # 输出节点的名称
                      dynamic_axes={'input' : {0 : 'batch_size'},    # 批处理维度动态
                                    'output' : {0 : 'batch_size'}})

    print(f"Model has been converted to ONNX and saved as {output_path}")

    厂家的秘方:OpenVINO、TensorRT

    不同厂家都有自己的推理秘制配方:推理引擎。这种趋势反映了 AI 领域的激烈竞争和快速创新。每家公司都希望在这场技术革命中占据有利地位,而自研推理引擎成为了关键战略。

    这种做法的核心原因在于硬件差异化和性能优化。不同公司拥有各自独特的硬件架构,如英特尔的 CPU、NVIDIA 的 GPU 或谷歌的 TPU。为了充分发挥这些硬件的潜力,定制化的推理引擎成为必然选择。这些引擎能够针对特定硬件进行深度优化,实现最佳的性能和效率。这其中,我将为大家简单介绍两种。分别是 OpenVINO 和 TensorRT。

    (一)OpenVINO

    OpenVINO

    让我们先将目光投向 OpenVINO。它的故事始于英特尔的实验室,在那里,一群充满激情的工程师梦想着如何让人工智能的力量触手可及。2018 年,OpenVINO 正式诞生,其名字中的"VINO"代表"Visual Inference and Neural network Optimization",寓意着它要为视觉智能和神经网络优化开辟一条康庄大道。

    OpenVINO 可在英特尔®硬件上扩展计算机视觉和非视觉工作负载,从而最大限度地提高性能。它通过从边缘到云的高性能,人工智能和深度学习推理来加速应用程序。

    关于OpenVINO的模型转换

    import subprocess
    import sys

    def convert_onnx_to_openvino(onnx_model_path, output_dir):
        cmd = [
            sys.executable,  # 使用当前Python解释器
            "-m""mo",  # 调用model optimizer
            "--input_model", onnx_model_path,
            "--output_dir", output_dir,
            "--data_type""FP32"
        ]
        
        subprocess.run(cmd, check=True)
        print(f"Model has been converted to OpenVINO IR format and saved in {output_dir}")

    # 使用示例
    onnx_model_path = "simple_net.onnx"
    output_dir = "openvino_model"

    convert_onnx_to_openvino(onnx_model_path, output_dir)

    这个转换过程和 ONNX 很像,在 OpenVINO 具体执行流程里分为反序列化,输入定义和前向执行几方面。

    (二)TensorRT

    TensorRT

    与此同时,在硅谷的另一端,NVIDIA 的工程师们也在编织着自己的 AI 梦想。2017 年,TensorRT 横空出世,它的名字中的"RT"代表"Runtime",彰显了它对高性能推理的执着追求。

    TensorRT 就像是一位技艺精湛的魔法师,它能够将庞大复杂的神经网络模型变成小巧高效的推理引擎。它的法术可以让模型在 NVIDIA 的 GPU 上飞驰,实现令人瞠目的低延迟和高吞吐量。想象一下,它就像是给AI装上了火箭推进器,让智能决策的速度突破音障。

    TensorRT 可用于对超大规模数据中心,嵌入式平台或自动驾驶平台进行推理加速。TensorRT 现已能支持 TensorFlow,Caffe,Mxnet,Pytorch 等几乎所有的深度学习框架,将 TensorRT 和 NVIDIA 的 GPU 结合起来,能在几乎所有的框架中进行快速和高效的部署推理。但可惜,TensorRT 是一个闭源的库。

    关于TensorRT模型的转换

    我们一般会给 TensorRT 的模型叫为 engine,我们可以使用 trt 提供的命令行工具,trtexec进行转换

    trtexec --onnx=simple_net.onnx --saveEngine=simple_net.trt --explicitBatch

    推理引擎:类似的执行流程

    • OpenVINO模型部署分为两个部分:模型优化器和推理引擎。

    模型优化器将训练好的模型转换为推理引擎可以识别的中间表达 –IR 文件,并在转换过程中对模型进行优化。推理引擎接受经过模型优化器转换并优化的网络模型,为 Intel 的各种计算设备提供高性能的神经网络推理运算。

    • TensorRT 模型部署也是分为两个部分:build 和 deployment 。

    build:这个阶段主要完成模型转换,将不同框架的模型转换到 TensorRT。模型转换时会完成前述优化过程中的层间融合,精度校准。这一步的输出是一个针对特定 GPU 平台和网络模型的优化过的 TensorRT 模型,这个 TensorRT 模型可以序列化存储到磁盘或内存中。存储到磁盘中的文件称之为 plan file。

    deployment:将上面一个步骤中的 plan 文件首先反序列化,并创建一个 runtime engine,然后就可以输入数据(比如测试集或数据集之外的图片),然后输出分类向量结果或检测结果。

    写在最后

    模型部署以加速为最终目的,首先就会抛弃易用性。这里特指静态图,在固定的范围内做极致的优化。除了模型上的优化,不同硬件厂商更会在贴近不同硬件上做各种底层上的优化。以获得在特定芯片上极致的性能。请期待后续部署教程吧~

    Reference

    1. https://blog.csdn.net/oakchina/article/details/123848097