Vitis AI 集成#

Vitis AI 是赛灵思(Xilinx)为在其平台上进行硬件加速的 AI 推理而开发的工具栈,适用于边缘设备和 Alveo 加速卡。它包含了优化的 IP 核、工具、库、模型以及示例设计。Vitis AI 以高效和易用为核心设计理念,旨在充分发挥赛灵思 FPGA 和自适应计算加速平台(ACAP)在 AI 加速方面的全部潜力。

当前 TVM 中的 Vitis AI 流程支持在边缘和云端加速神经网络模型推理,适用于以下平台:Zynq Ultrascale+ MPSocAlveoVersal。支持的边缘和云端深度学习处理器单元(DPU)的标识符为:

Target Board

DPU ID

TVM Target ID

ZCU104

DPUCZDX8G

DPUCZDX8G-zcu104

ZCU102

DPUCZDX8G

DPUCZDX8G-zcu102

Kria KV260

DPUCZDX8G

DPUCZDX8G-kv260

VCK190

DPUCVDX8G

DPUCVDX8G

VCK5000

DPUCVDX8H

DPUCVDX8H

U200

DPUCADF8H

DPUCADF8H

U250

DPUCADF8H

DPUCADF8H

U50

DPUCAHX8H / DPUCAHX8L

DPUCAHX8H-u50 / DPUCAHX8L

U280

DPUCAHX8H / DPUCAHX8L

DPUCAHX8H-u280 / DPUCAHX8L

For more information about the DPU identifiers see following table:

DPU

Application

HW Platform

Quantization Method

Quantization Bitwidth

Design Target

Deep Learning
Processing Unit
C: CNN
R: RNN
AD: Alveo DDR
AH: Alveo HBM
VD: Versal DDR with AIE & PL
ZD: Zynq DDR
X: DECENT
I: Integer threshold
F: Float threshold
R: RNN
4: 4-bit
8: 8-bit
16: 16-bit
M: Mixed Precision
G: General purpose
H: High throughput
L: Low latency
C: Cost optimized

在本页中,您将找到有关如何在不同平台(Zynq、Alveo、Versal)上 设置 TVM 与 Vitis AI 的信息,以及如何开始 编译模型 并在不同平台上执行推理:推理

系统要求#

Vitis AI 系统要求页面 列出了运行 Docker 容器以及在 Alveo 加速卡上执行任务的系统要求。对于边缘设备(例如 Zynq),部署模型需要一台主机用于通过 TVM 与 Vitis AI 流程编译模型,以及一台边缘设备用于运行编译后的模型。主机的系统要求与上述链接中的要求相同。

安装说明#

本节提供了为云端和边缘设备设置 TVM 与 Vitis AI 流程的说明。TVM 对 Vitis AI 的支持通过 Docker 容器提供。所提供的脚本和 Dockerfile 将 TVM 和 Vitis AI 编译到镜像中。

  1. 克隆 TVM 仓库

    git clone --recursive https://github.com/apache/tvm.git
    cd tvm
    
  2. 构建并启动 TVM - Vitis AI Docker 容器。

    ./docker/build.sh demo_vitis_ai bash
    ./docker/bash.sh tvm.demo_vitis_ai
    
    # Setup inside container
    conda activate vitis-ai-tensorflow
    
  3. 在容器内使用 Vitis AI 构建 TVM(在 tvm 目录内)

    mkdir build
    cp cmake/config.cmake build
    cd build
    echo set\(USE_LLVM ON\) >> config.cmake
    echo set\(USE_VITIS_AI ON\) >> config.cmake
    cmake ..
    make -j$(nproc)
    
  4. 安装 TVM

    cd ../python
    pip3 install -e . --user
    

在此 Docker 容器内,您现在可以为云端和边缘目标编译模型。若要在容器内运行于云端 Alveo 或 Versal VCK5000 加速卡上,请分别遵循 AlveoVersal VCK5000 的设置说明。若要为推理设置您的 Zynq 或 Versal VCK190 评估板,请分别遵循 ZynqVersal VCK190 的说明。

Alveo 设置#

请查看以下页面以获取设置信息:Alveo 设置

设置完成后,您可以在 Docker 容器内通过以下方式选择正确的 DPU:

cd /workspace
git clone --branch v1.4 --single-branch --recursive https://github.com/Xilinx/Vitis-AI.git
cd Vitis-AI/setup/alveo
source setup.sh [DPU-IDENTIFIER]

其 DPU 标识符可以在本页顶部的 DPU 目标表格的第二列中找到。

Versal VCK5000 Setup#

Check out following page for setup information: VCK5000 Setup.

设置完成后,您可以在 Docker 容器内通过以下方式选择正确的 DPU:

cd /workspace
git clone --branch v1.4 --single-branch --recursive https://github.com/Xilinx/Vitis-AI.git
cd Vitis-AI/setup/vck5000
source setup.sh

Zynq Setup#

对于 Zynq 目标(DPUCZDX8G),编译阶段将在主机上的 Docker 容器内运行。除了构建 TVM - Vitis AI Docker 外,这不需要任何特定的设置。要执行模型,首先需要设置 Zynq 开发板,更多相关信息可以在这里找到。

  1. 下载适用于您目标的 Petalinux 镜像:
  2. 使用 Etcher 软件将镜像文件烧录到 SD 卡上。

  3. 将带有镜像的 SD 卡插入目标开发板。

  4. 插入电源并使用串口启动开发板以操作系统。

  5. 使用串口设置开发板的 IP 信息。有关步骤 1 到 5 的更多详细信息,请参阅 设置评估板

  6. 在开发板上创建 4GB 的交换空间

fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo "/swapfile swap swap defaults 0 0" >> /etc/fstab
  1. 安装 hdf5 依赖项(需要 30 分钟到 1 小时完成)

cd /tmp && \
  wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.10/hdf5-1.10.7/src/hdf5-1.10.7.tar.gz && \
  tar -zxvf hdf5-1.10.7.tar.gz && \
  cd hdf5-1.10.7 && \
  ./configure --prefix=/usr && \
  make -j$(nproc) && \
  make install && \
  cd /tmp && rm -rf hdf5-1.10.7*
  1. 安装 Python 依赖项

pip3 install Cython==0.29.23 h5py==2.10.0 pillow
  1. 安装 PyXIR

git clone --recursive --branch rel-v0.3.1 --single-branch https://github.com/Xilinx/pyxir.git
cd pyxir
sudo python3 setup.py install --use_vart_edge_dpu
  1. 构建并安装带有 Vitis AI 的 TVM

git clone --recursive https://github.com/apache/tvm
cd tvm
mkdir build
cp cmake/config.cmake build
cd build
echo set\(USE_LLVM OFF\) >> config.cmake
echo set\(USE_VITIS_AI ON\) >> config.cmake
cmake ..
make tvm_runtime -j$(nproc)
cd ../python
pip3 install --no-deps  -e .
  1. 在 Python shell 中检查设置是否成功:

python3 -c 'import pyxir; import tvm'

备注

您可能会看到一条关于未找到 'cpu-tf' 运行时的警告。此警告在开发板上是预期的,可以忽略。

Versal VCK190 Setup#

对于 Versal VCK190 的设置,请遵循 Zynq 设置 的说明,但在步骤 1 中使用 VCK190 镜像。其他步骤相同。

编译模型#

带有 Vitis AI 的 TVM 流程包含两个阶段:编译和推理。在编译期间,用户可以选择为当前支持的云端或边缘目标设备编译模型。编译完成后,生成的文件可用于在 推理 阶段在指定的目标设备上运行模型。目前,带有 Vitis AI 的 TVM 流程支持部分赛灵思数据中心和边缘设备。

在本节中,将介绍在 TVM 中使用 Vitis AI 编译模型的典型流程。

导入

确保导入 PyXIR 和 DPU 目标(对于 DPUCADF8H,使用 import pyxir.contrib.target.DPUCADF8H):

import pyxir
import pyxir.contrib.target.DPUCADF8H

import tvm
import tvm.relay as relay
from tvm.contrib.target import vitis_ai
from tvm.contrib import utils, graph_executor
from tvm.relay.op.contrib.vitis_ai import partition_for_vitis_ai

声明目标

tvm_target = 'llvm'
dpu_target = 'DPUCADF8H' # options: 'DPUCADF8H', 'DPUCAHX8H-u50', 'DPUCAHX8H-u280', 'DPUCAHX8L', 'DPUCVDX8H', 'DPUCZDX8G-zcu104', 'DPUCZDX8G-zcu102', 'DPUCZDX8G-kv260'

带有 Vitis AI 的 TVM 流程目前支持本页顶部表格中列出的 DPU 目标。一旦定义了适当的目标,调用 TVM 编译器为指定的目标构建图。

导入模型

导入 MXNet 模型的示例代码:

mod, params = relay.frontend.from_mxnet(block, input_shape)

模型分区

导入模型后,利用 Relay API 为提供的 DPU 目标注释 Relay 表达式并对图进行分区。

mod = partition_for_vitis_ai(mod, params, dpu=dpu_target)

构建模型

将分区后的模型传递给 TVM 编译器,以生成 TVM 运行时的运行时库。

export_rt_mod_file = os.path.join(os.getcwd(), 'vitis_ai.rtmod')
build_options = {
    'dpu': dpu_target,
    'export_runtime_module': export_rt_mod_file
}
with tvm.transform.PassContext(opt_level=3, config={'relay.ext.vitis_ai.options': build_options}):
    lib = relay.build(mod, tvm_target, params=params)

量化模型

通常,为了能够使用 Vitis AI DPU 加速器加速神经网络模型的推理,这些模型需要提前量化。在 TVM - Vitis AI 流程中,利用即时量化来消除这一额外的预处理步骤。在此流程中,用户无需提前量化模型,而是可以使用典型的推理执行调用(module.run)通过提供的前 N 个输入即时量化模型(详见下文)。这将设置并校准 Vitis-AI DPU,从那时起,所有后续输入的推理都将被加速。请注意,边缘流程与上述流程略有不同,因为在提供前 N 个输入后,推理不会立即加速,但模型将被量化和编译,并可以移动到边缘设备进行部署。更多信息请查看下面的 在 Zynq 上运行 部分。

module = graph_executor.GraphModule(lib["default"](tvm.cpu()))

# First N (default = 128) inputs are used for quantization calibration and will
# be executed on the CPU
# This config can be changed by setting the 'PX_QUANT_SIZE' (e.g. export PX_QUANT_SIZE=64)
for i in range(128):
   module.set_input(input_name, inputs[i])
   module.run()

默认情况下,用于量化的图像数量设置为 128。您可以使用 PX_QUANT_SIZE 环境变量更改用于即时量化的图像数量。例如,在调用编译脚本之前,在终端中执行以下行,将量化校准数据集减少到八张图像。这可以用于快速测试。

export PX_QUANT_SIZE=8

最后,将 TVM 编译器的编译输出存储在磁盘上,以便在目标设备上运行模型。对于云端 DPU(Alveo、VCK5000),操作如下:

lib_path = "deploy_lib.so"
lib.export_library(lib_path)

对于边缘目标(Zynq、VCK190),需要为 aarch64 重新构建。为此,首先需要正常导出模块以序列化 Vitis AI 运行时模块(vitis_ai.rtmod)。之后,将再次加载此运行时模块以重新构建并导出为 aarch64。

temp = utils.tempdir()
lib.export_library(temp.relpath("tvm_lib.so"))

# Build and export lib for aarch64 target
tvm_target = tvm.target.arm_cpu('ultra96')
lib_kwargs = {
   'fcompile': contrib.cc.create_shared,
   'cc': "/usr/aarch64-linux-gnu/bin/ld"
}

build_options = {
    'load_runtime_module': export_rt_mod_file
}
with tvm.transform.PassContext(opt_level=3, config={'relay.ext.vitis_ai.options': build_options}):
     lib_edge = relay.build(mod, tvm_target, params=params)

lib_edge.export_library('deploy_lib_edge.so', **lib_kwargs)

本教程到此结束,介绍了如何使用 TVM 与 Vitis AI 编译模型。有关如何运行编译模型的说明,请参阅下一节。

推理#

带有 Vitis AI 的 TVM 流程包含两个阶段:编译和推理。在编译期间,用户可以选择为当前支持的任何目标设备编译模型。编译完成后,生成的文件可用于在推理阶段在目标设备上运行模型。

请查看 在 Alveo 和 VCK5000 上运行在 Zynq 和 VCK190 上运行 部分,了解如何在云端加速卡和边缘开发板上进行推理。

在 Alveo 和 VCK5000 上运行#

在按照 编译模型 部分的步骤操作后,您可以继续在 Docker 内对新输入进行加速推理:

module.set_input(input_name, inputs[i])
module.run()

或者,您可以加载导出的运行时模块(在 编译模型 中导出的 deploy_lib.so):

import pyxir
import tvm
from tvm.contrib import graph_executor

dev = tvm.cpu()

# input_name = ...
# input_data = ...

# load the module into memory
lib = tvm.runtime.load_module("deploy_lib.so")

module = graph_executor.GraphModule(lib["default"](dev))
module.set_input(input_name, input_data)
module.run()

在 Zynq 和 VCK190 上运行#

在继续之前,请遵循 ZynqVersal VCK190 的设置说明。

在开发板上运行模型之前,您需要为目标评估板编译模型并将编译后的模型传输到开发板上。有关如何编译模型的信息,请参阅 编译模型 部分。

之后,您需要将编译后的模型(deploy_lib_edge.so)传输到评估板上。然后,在开发板上,您可以使用典型的 "load_module" 和 "module.run" API 来执行。为此,请确保以 root 身份运行脚本(在终端中执行 su 以登录 root)。

备注

还请注意,您**不应**在运行脚本中导入 PyXIR DPU 目标(import pyxir.contrib.target.DPUCZDX8G)。

import pyxir
import tvm
from tvm.contrib import graph_executor

dev = tvm.cpu()

# input_name = ...
# input_data = ...

# load the module into memory
lib = tvm.runtime.load_module("deploy_lib_edge.so")

module = graph_executor.GraphModule(lib["default"](dev))
module.set_input(input_name, input_data)
module.run()