TVM 执行提供程序

TVM 是一个基于 Apache TVM 构建的 ONNX Runtime 执行提供程序。它允许 ONNX Runtime 用户利用 Apache TVM 的模型优化。TVM EP 目前处于“预览”阶段。它已在 Linux 和 Windows 上通过少量模型的测试,但在 MacOS 上尚未测试。

目录

使用 TVM 执行提供程序构建 ONNX Runtime

Linux

在 Ubuntu/Debian 等 Linux 操作系统上安装最低先决条件

apt-get install -y python3 python3-dev python3-pip python3-setuptools gcc libtinfo-dev zlib1g-dev build-essential cmake libedit-dev libxml2-dev llvm-12
pip3 install numpy decorator attrs nasm

注意:由于带有 TVM EP 的 ONNX Runtime 是使用 Intel ipp-crypto 库构建的,因此有新的要求。编译器 gcc (和 g++) 版本应等于或高于 8.2。nasm 版本应为 2.14.02 或更高。nasm 版本过小的问题可见 此处此处。对于 Ubuntu LTS 18,由于其版本为 2.13.02,apt-get install nasm 不够,请参阅 此处 从源代码安装的说明。

此外,当前实现支持 TVM EP 的 NVidia GPU。目前,您只能使用支持 CUDA Toolkit 的 NVidia GPU。为此,请确保您已安装 NVidia 驱动程序和 CUDA Toolkit。更详细的说明可在 官方页面 上找到。

克隆此仓库。为了构建 ONNXRT,您需要 CMake 3.18 或更高版本。在 Ubuntu 20.04 中,您可以使用以下命令安装最新版本的 CMake

sudo apt-get update
sudo apt-get install gpg wget

wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null

echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null
sudo apt-get update

sudo rm /usr/share/keyrings/kitware-archive-keyring.gpg
sudo apt-get install kitware-archive-keyring

sudo apt-get install cmake

构建 ONNX Runtime (TVM x86)

./build.sh --config Release --enable_pybind --build_wheel --parallel --skip_tests --skip_onnx_tests --use_tvm

构建 ONNX Runtime (TVM with CUDA support)

./build.sh --config Release --enable_pybind --build_wheel --parallel --skip_tests --skip_onnx_tests --use_tvm --tvm_cuda_runtime

此命令同时构建 TVMonnxruntime-tvm。它为每个项目创建两个 wheel 包。构建 ONNX Runtime 的 Python API,而不是使用标准包。相关说明如下。

TVM 包

cd <path_to_onnx_runtime>
python3 -m pip uninstall tvm -y
whl_path=$(find ./build/<OS_NAME>/Release/_deps/tvm-src/python/dist -name "*.whl")
python3 -m pip install $whl_path

TVM EP 包

cd <path_to_onnx_runtime>
python3 -m pip uninstall onnxruntime onnxruntime-tvm -y
whl_path=$(find ./build/<OS_NAME>/Release/dist -name "*.whl")
python3 -m pip install $whl_path

或者,您可以设置 PYTHONPATH 来告诉 python 在哪里找到 ONNXRT 库和 TVM 库。

export PYTHONPATH=<path_to_onnx_runtime>/build/<OS_NAME>/Release:${PYTHONPATH}
export PYTHONPATH=<path_to_onnx_runtime>/build/<OS_NAME>/Release/_deps/tvm-src/python:${PYTHONPATH}

Windows

在 Windows 上安装最低先决条件:Git, CMake, Visual Studio, Python, LLVM

  • Git:从 此处 下载并安装 Git for Windows。请确保 git.exe 的路径已包含在环境变量中。默认情况下,它应该会被添加。安装后,在命令行 (cmd) 中使用 git --version 检查 git。
  • CMake:使用 此链接 下载并安装 CMake。推荐使用 msi 文件。在 cmd 中使用 cmake --version 验证 CMake 安装。
  • Visual Studio:从 此处 下载并分别安装 Visual Studio 20** Community 和 Visual Studio Build Tools。建议不要更改默认安装路径。选择“使用 C++ 的桌面开发”工作负载,并确保同时选中“MSVC [当代版本] C++ 构建工具”和“Windows 10 SDK”两个选项。
  • Python:从 此处 下载并安装 Python 3.*。请务必勾选“将 Python 添加到 PATH”选项,这样安装程序会将 Python 目录直接包含到环境变量中。安装后,在 cmd 中使用 python 检查 python。预期输出如下所示
    Python 3.10.5 (tags/v3.10.5:f377153, Jun  6 2022, 16:14:13) [MSC v.1929 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>>
    

    使用 quit() 退出 python 界面。

  • LLVM:编译器对于纯 ONNX Runtime 安装不是必需的,但默认情况下 TVM EP 需要它。
    git clone --depth 1 --branch release/11.x https://github.com/llvm/llvm-project.git
    cmake -S llvm -B build -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -DLLVM_TARGETS_TO_BUILD=X86 -Thost=x64 -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022"
    cmake --build ./build --config Release
    
  • ipp-crypto 的依赖项
    1. 通过以下行在 Windows 上安装 asm 编译器 (nasm)
      winget install nasm -i
      

                将其添加到 PATH(Windows GUI 的说明可见 此处)或通过 cmd

      set PATH="%PATH%;C:\Program Files\NASM"
      

                在命令提示符下通过 nasm --version 检查。
            

    2. 此处 通过 msi 文件在 Windows 上安装 openssl。将包含可执行文件的目录路径(例如“C:\Program Files\OpenSSL-Win64\bin”)添加到 PATH(请参阅上述说明)。
                在命令提示符下通过 openssl version 检查。

要使用 NVIDIA GPU(可选),应安装 CUDA 和 cuDNN。

  • CUDA:通过 此链接 安装 CUDA。
  • cuDNN:从 此处 下载 cuDNN 安装程序。选择与 CUDA v11.* 对应的 v8.*,解压后按以下方式移动 cuDNN 文件
    1. [解压目录]\bin\ → C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\bin
    2. [解压目录]\include\ → C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\include
    3. [解压目录]\lib\ → C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\lib

在 cmd 中使用 nvcc --version 验证 CUDA 安装。

从源代码构建带 TVM 执行提供程序的 ONNX Runtime

  • 使用命令行从 github 克隆源代码
    git clone --recursive https://github.com/Microsoft/onnxruntime
    cd onnxruntime
    
  • CPU 构建
    build.bat --config Release --enable_pybind --build_wheel --skip_tests --parallel --use_tvm --skip_onnx_tests --cmake_generator "Visual Studio 17 2022" --llvm_config <path_to_llvm_root>/build/Release/bin/llvm-config.exe
    
  • GPU 构建
    build.bat --config Release --enable_pybind --build_wheel --skip_tests --parallel --use_tvm --skip_onnx_tests --cmake_generator "Visual Studio 17 2022" --llvm_config <path_to_llvm_root>/build/Release/bin/llvm-config.exe --use_cuda --cudnn_home “C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.*” --cuda_home “C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.*”
    

    在两种情况下(CPU,GPU),cmake 生成器都有以下选项:“Visual Studio 15 2017”、“Visual Studio 16 2019”、“Visual Studio 17 2022”和“Ninja”

  • 安装 ONNX Runtime 的 python wheel 包
    包的默认路径是 <path_to_onnxruntime_root>/build/Windows/Release/Release/dist。请注意,它与 Linux 上包的路径不同。在安装之前,请检查 wheel 包的名称并使用对应的包。它可能看起来像这样
    python -m pip install .\onnxruntime\build\Windows\Release\Release\dist\onnxruntime_tvm-1.6.0-cp37-cp37m-win_amd64.whl
    
  • 安装 TVM 的 python wheel 包,因为 TVM EP 内部使用了它的 python API
    它可能看起来像这样
    python -m pip install .\onnxruntime\build\Windows\Release\_deps\tvm-src\python\dist\tvm-0.9.dev1728+g3425ed846-cp39-cp39-win_amd64.whl
    
  • 通过 python 脚本验证结果。注意:python 不应从包含“onnxruntime”目录的目录中启动,以获得正确结果。
    import onnxruntime
    print(onnxruntime.__version__)
    print(onnxruntime.get_device())
    print(onnxruntime.get_available_providers())
    
  • 卸载过程
    pip uninstall onnxruntime-tvm
    

配置选项

TVM Executor Provider 可以通过以下提供程序选项进行配置

po = [dict(executor=tvm_executor_type,
           so_folder=folder_with_pretuned_files,
           check_hash=check_hash,
           hash_file_path=hash_file_path,
           target=client_target,
           target_host=client_target_host,
           opt_level=client_opt_level,
           freeze_weights=freeze,
           to_nhwc=layout_transform,
           tuning_type=tvm_optimizer_type,
           tuning_file_path=client_tuning_logfile,
           input_names = input_names_str,
           input_shapes = input_shapes_str)]
tvm_session = onnxruntime.InferenceSession(model_path, providers=["TvmExecutionProvider"], provider_options=po)


  • executor 是 TVM 使用的执行器类型。有两种选择:GraphExecutor 和 VirtualMachine,分别对应“graph”和“vm”标签。默认使用 VirtualMachine。
  • so_folder 是包含模型调优后获得的一组文件(.ro-、.so/.dll 文件和权重)的文件夹路径。它使用这些文件进行执行器编译,而不是 onnx 模型。但 ONNX Runtime 仍然需要后者。
  • check_hash 意味着需要对 so_folder 参数中获得的模型执行 HASH 检查。默认值为 False
  • hash_file_path 是包含 ONNX 模型预计算 HASH 的文件路径,该模型调优结果位于 so_folder 参数传递的路径中。如果传入空字符串作为此值,则文件将在 so_folder 参数中传递的文件夹中搜索。
  • targettarget_host 是 TVM 中的字符串(例如“llvm –mcpu=avx2”)。使用加速器时,target 可能类似于 cuda,而 target_host 可能为 llvm -mtriple=x86_64-linux-gnu
  • opt_level 是 TVM 优化级别。默认为 3
  • freeze_weights 意味着所有模型权重在编译阶段都被保留,否则它们会在每次推理时下载。为获得最佳性能,推荐使用 True。默认值为 true。
  • to_nhwc 开启特殊的模型转换,特别是数据布局,其中使用了 Octomizer。它允许正确处理从 Octomizer 获得的调优日志。默认值为 false。
  • tuning_type 定义了正在使用的 TVM 调优日志类型,可以设置为 AutoTVM(第一代自动调优日志)或 Ansor(第二代自动调优日志)。默认情况下,此选项设置为 AutoTVM
  • tuning_file_path 是 AutoTVM 或 Ansor 调优文件的路径,该文件为给定模型和目标提供最佳性能的规范。(更多详情请参见下文)。

TVM 仅支持固定图模型。如果您的模型在输入形状中具有未知维度(不包括批大小),您必须使用 input_namesinput_shapes 提供程序选项提供形状。下面是必须传递给 provider_options 的示例

input_names = "input_1 input_2"
input_shapes = "[1 3 224 224] [1 2]"

性能调优

TVM 通过自动化调优过程优化机器学习模型,该过程生成针对目标硬件架构的模型变体。此过程还会生成“调优日志”,TVM EP 依赖这些日志来最大化模型性能。您可以通过以下方式获取模型的这些日志

AutoTVM:https://tvm.apache.ac.cn/docs/how_to/tune_with_autotvm/index.html

Ansor (自动调度):https://tvm.apache.ac.cn/docs/how_to/tune_with_autoscheduler/index.html

将 TVM EP 与 TVM 调优日志一起使用还需要用户关闭 ONNX Runtime 预处理。为此,可以使用以下 SessionOptions()

so = onnxruntime.SessionOptions()
so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL

tvm_session = onnxruntime.InferenceSession(model_path, sess_options=so, providers=["TvmExecutionProvider"], provider_options=po)

使用预编译模型

也可以使用预编译模型。

编译后的模型可以通过 OctoML 平台 获得或直接编译(有关模型编译的更多信息,请参阅 ResNet50 推理与 TVM EP 示例笔记本 中的支持预编译模型部分)。

为了使用预编译模型,只需要传递两个选项

  • executor - 必须使用 vm (VirtualMachine) 作为值(GraphExecutor 不支持此功能);
  • so_folder - 必须将预编译模型文件所在的目录路径作为值传递。
  • check_hash - (可选)如果您想检查哈希,必须传递 True 作为值。
  • hash_file_path - (可选)默认情况下,将从 so_folder 参数中传递的目录中搜索包含调优模型哈希的文件。如果您想指定不同的位置,则必须传递包含所需哈希的文件的路径作为值。

您可以在上面的 配置选项 部分阅读有关这些选项的更多信息。

示例

已知问题

  • 目前,TVM EP 仅在 UNIX/Linux 和 Windows 系统上进行了验证。
  • ONNX 和 Google protobuf 之间发现了一些兼容性问题。AttributeError: module 'google.protobuf.internal.containers' has no attribute 'MutableMapping'。这通常在 protobuf 版本 >= 3.19.0 且 ONNX 版本 <= 1.8.1 的任何 python 脚本中 import onnx 时发生。要解决此问题,可以单独或一起重新安装 Google protobuf 和 ONNX,使用
    pip3 uninstall onnx -y
    pip3 install onnx==1.10.1
    pip3 uninstall protobuf -y
    pip3 install protobuf==3.19.1
    

以下 ONNX 和 protobuf 版本被发现兼容

  • 3.17.3 和 1.8.0
  • 3.19.1 和 1.10.1