Vitis AI 整合

發表於2024-02-12

更多 TVM 中文檔案可訪問 →Apache TVM 是一個端到端的深度學習編譯框架,適用於 CPU、GPU 和各種機器學習加速晶片。IApache TVM 中文站
Vitis AI 是用在 Xilinx 平臺(包括邊緣裝置和 Alveo 卡)上進行硬體加速 AI 推理的 Xilinx 開發堆疊。它由最佳化的 IP、工具、庫、模型和示例設計組成。在設計時兼顧高效率和易用性,充分發揮了 Xilinx FPGA 和 ACAP 上 AI 加速的潛力。

TVM 中當前的 Vitis AI 流支援使用 Zynq Ultrascale+ MPSoc, Alveo Versal 平臺在邊緣和雲端加速神經網路模型推理。支援的邊緣和雲深度學習處理器單元(DPU)的識別符號是:

Target BoardDPU IDTVM Target ID
ZCU104DPUCZDX8GDPUCZDX8G-zcu104
ZCU102DPUCZDX8GDPUCZDX8G-kv260
Kria KV260DPUCZDX8GDPUCZDX8G-kv260
VCK190DPUCVDX8GDPUCVDX8G
VCK5000DPUCVDX8HDPUCVDX8H
U200DPUCADF8HDPUCADF8H
U250DPUCADF8HDPUCADF8H
U50DPUCAHX8H / DPUCAHX8LDPUCAHX8H-u50 / DPUCAHX8L
U280DPUCAHX8H / DPUCAHX8LDPUCAHX8H-u280 / DPUCAHX8L

有關 DPU 識別符號的更多資訊,參見下表:

DPUApplicationHW PlatformQuantization MethodQuantization BitwidthDesign Target
Deep LearningProcessing UnitC: CNNR: RNNAD: Alveo DDRAH: Alveo HBMVD: Versal DDR with AIE & PLZD: Zynq DDRX: DECENTI: Integer thresholdF: Float thresholdR: RNN4: 4-bit8: 8-bit16: 16-bitM: Mixed PrecisionG: General purposeH: High throughputL: Low latencyC: Cost optimized

此教程介紹有關如何在不同平臺(Zynq、Alveo、Versal)上使用 Vitis AI 設定 TVM 以及如何開始 編譯模型 並在不同平臺上執行:推理。

系統要求V

Vitis AI 系統要求頁面 列出了執行 Docker 容器以及在 Alveo 卡上執行的系統要求。對於邊緣裝置(例如 Zynq),部署模型需要使用帶有 Vitis AI 流程的 TVM 編譯模型的主機,以及用於執行編譯模型的邊緣裝置。主機系統要求與上面連結中指定的相同。

設定說明

本節介紹如何用 Vitis AI 流為雲和邊緣設定 TVM。支援 Vitis AI 的 TVM 是透過 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 容器中可以為雲和邊緣目標編譯模型。要在 docker 容器內的雲 Alveo 或 Versal VCK5000 卡上執行,按照 Alveo 或者 Versal VCK5000 設定說明進行操作。分別參照 Zynq 和 Versal VCK190,為推理過程設定 Zynq 或 Versal 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 Targets 表的第二列中找到此 DPU 識別符號。

Versal VCK5000 設定

檢視 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 設定

除了構建 TVM - Vitis AI docker 之外,對於 Zynq 目標(DPUCZDX8G),編譯階段在主機上的 docker 內執行,不需要任何特定設定。執行模型時,首先要設定 Zynq 板,更多資訊如下。

1.下載 Petalinux 映象:

  • ZCU104
  • ZCU102
  • Kria KV260
    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

7.安裝 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*

8.安裝 Python 依賴

pip3 install Cython==0.29.23 h5py==2.10.0 pillow

9.安裝 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

10.用 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 .

11.在 Python shell 中檢查設定是否成功:

python3 -c 'import pyxir; import tvm'
備註
可能會看到有關未找到 "cpu-tf" runtime 的警告,可以忽略。

Versal VCK190 設定

參考 Zynq 設定 設定 Versal VCK190,但在步驟 1 中參考 VCK190 映象。其他步驟相同。

編譯模型

帶有 Vitis AI 流的 TVM 包含編譯和推理兩個階段。在編譯期間,使用者可以為當前支援的雲或邊緣目標裝置選擇要編譯的模型。編譯模型生成的檔案可用於在 推理 階段在指定的目標裝置上執行模型。目前,採用 Vitis AI 流程的 TVM 支援選定數量的 Xilinx 資料中心和邊緣裝置。

本節介紹在 TVM 中用 Vitis AI 編譯模型的一般流程。

匯入

確保匯入 PyXIR 和 DPU target(為 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

宣告 Target

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

帶有 Vitis AI 流的 TVM 目前支援本頁頂部表格中列出的 DPU targets。一旦定義了恰當的 target,就會呼叫 TVM 編譯器來為指定的 target 構建計算圖。

匯入模型

匯入 MXNet 模型的示例程式碼:

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

對模型分割槽

匯入模型後,用 Relay API 為 DPU target 註釋 Relay 表示式,並對計算圖進行分割槽。

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

構建模型

將分割槽模型傳給 TVM 編譯器,然後生成 TVM Runtime 的 runtime 庫。

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()))

# 前 N 個(預設 = 128)輸入用於量化校準,並在 CPU 上執行
# 可以透過設定 “PX_QUANT_SIZE” 來更改此配置(例如,匯出 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)

對於邊緣 target(Zynq 和 VCK190),必須為 aarch64 重建。因此首先必須正常匯出模組,並同時序列化 Vitis AI runtime 模組(vitis_ai.rtmod)。之後再次載入此 runtime 模組,為 aarch64 重建和匯出。

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

# 為 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()

或者載入匯出的 runtime 模組(在 編譯模型 中匯出的 deploy_lib.so):

import pyxir
import tvm
from tvm.contrib import graph_executor

dev = tvm.cpu()

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

# 將模組載入到記憶體
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 上執行

開始前按照 Zynq 或 Versal VCK190 設定說明進行設定。

在單板上執行模型之前,需要為目標評估單板編譯模型,並將編譯後的模型傳輸到板上。如何編譯模型,參閱 編譯模型 部分。

之後將編譯好的模型(deploy_lib_edge.so)傳輸到評估單板,然後可以在板上使用典型的「load_module」和「module.run」API 來執行。確保以 root 身份執行指令碼(在終端中執行 su 登入到 root)。

備註
不要在執行指令碼(import pyxir.contrib.target.DPUCZDX8G)中匯入 PyXIR DPU targets。
import pyxir
import tvm
from tvm.contrib import graph_executor

dev = tvm.cpu()

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

# 將模組載入到記憶體
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()