使用 VOE 进行编程 - 3.5 简体中文

Vitis AI 用户指南 (UG1414)

Document ID
UG1414
Release Date
2023-09-28
Version
3.5 简体中文

ONNX 运行时

Vitis AI Execution Provider (Vitis AI EP) 提供了含 AMD DPU 的硬件加速 AI 推断。它支持用户在目标开发板上直接运行已量化的 ONNX 模型。当前,ONNX Runtime 内的 Vitis AI EP 支持在嵌入式器件上进行神经网络模型推断加速,这类器件包括 Zynq UltraScale+ MPSoCVersalVersal AI EdgeKria 卡。

Vitis AI ONNXRuntime Engine (VOE) 充当的是 Vitis AI EP 的实现库。

图 1. VOE 概述

功能特性

  • 支持 ONNX Opset v18、ONNX Runtime 1.16.0 和 ONNX v1.13
  • C++ 和 Python API(受 Python v3 支持)
  • Vitis AI EP 外,还支持结合其他执行提供程序(如 ACL EP)利用 AMD DPU 来加速推断
  • 支持在 ARM64 Cortex®-A72 核上执行计算,受支持的目标为 VAI3.5 中的 VEK280

益处

  • 通用性:您可在 AMD DPU 上部署子计算图,同时使用 Arm® NN 和 Arm® ACL 之类的其他执行提供程序来处理其他运算符。这种灵活性支持在目标板上部署目标板不予直接支持的模型。
  • 改善性能:您可通用 AMD DPU 之类的专用执行提供程序来处理特定运算,并使用其他提供程序来处理其余运算符,从而为自己的模型实现最优化的性能。
  • 扩展模型支持:增强 ONNX Runtime 即可支持部署含有 DPU 原生不支持的运算符的模型。您可通过整合其他执行提供程序来执行多种多样的模型,包括来自 ONNX model zoo 的模型。

运行时选项

Vitis AI ONNX Runtime 集成了编译器,用于将模型计算图和权重编译为微码可执行文件。该可执行文件部署在目标加速器上。

在启动 ONNX Runtime 会话期间进行模型编译,此编译进程必须在成功完成首次推断之前完成。编译时间可能不尽相同,但可能需要几分钟时间。完成模型编译后,即可缓存模型可执行文件。对于后续推断运行,您可使用缓存的可执行模型。

您可设置多个运行时变量用于配置推断会话,如下表所示。config_file 变量并非可选,必须将其设为指向配置文件所在位置。cacheDir 变量和 cacheKey 变量均为可选。

表 1. 运行时变量
运行时变量 默认值 详细信息

config_file

"" (必需)表示配置文件路径,配置文件 vaip_config.json 包含在 Vitis_ai_2023.1-r3.5.0.tar.gz 内
cacheDir

/tmp/{user}/vaip/.cache/

(可选)表示高速缓存目录

cacheKey

{onnx_model_md5}

(可选)表示高速缓存密钥,用于区分不同模型。

最终高速缓存目录为 {cacheDir}/{cacheKey}。此外,还可设置环境变量以自定义 Vitis AI EP。

表 2. 环境变量

环境变量

默认值

详细信息

XLNX_ENABLE_CACHE

1

对应是否使用高速缓存,如果设为 0,则将忽略缓存的可执行文件,并且将重新编译模型。

XLNX_CACHE_DIR

/tmp/$USER/vaip/.cache/{onnx_model_md5}

(可选)表示配置高速缓存路径

安装与部署

Vitis AI 3.5 提供了十多个基于 ONNX Runtime 的部署示例。您可在 https://github.com/Xilinx/Vitis-AI/tree/v3.5/examples/vai_library/samples_onnx 中找到这些示例。以下步骤描述了如何使用 VOE 来部署 ONNX 模型:

  1. 准备 ONNX 格式的量化模型。使用 Vitis AI 量化器来量化模型,并输出 ONNX 格式的量化模型。
  2. 下载 ONNX Runtime 包 vitis_ai_2023.1-r3.5.0.tar.gz 并将其安装在目标开发板上。
    tar -xzvf vitis_ai_2023.1-r3.5.0.tar.gz -C /
    然后,下载 voe-0.1.0-py3-none-any.whlonnxruntime_vitisai-1.16.0-py3-none-any.whl。确保器件已联机,并在线安装这两个包。
    pip3 install voe*.whl
    pip3 install onnxruntime_vitisai*.whl
  3. Vitis AI 3.5 支持 ONNX Runtime C++ API 和 Python API。如需了解 ONNX Runtime API 的详细信息,请访问 https://onnxruntime.ai/docs/api/。以下提供了基于 C++ API 的 ONNX 模型部署代码片段:

    C++ 示例

    // ...
    #include <experimental_onnxruntime_cxx_api.h>
    // include user header files
    // ...
    
    auto onnx_model_path = "resnet50_pt.onnx"
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "resnet50_pt");
    auto session_options = Ort::SessionOptions();
    
    auto options = std::unorderd_map<std::string,std::string>({});
    options["config_file"] = "/etc/vaip_config.json";
    // optional, eg: cache path : /tmp/my_cache/abcdefg // Replace abcdefg with your model name, eg. onnx_model_md5
    options["cacheDir"] = "/tmp/my_cache";
    options["cacheKey"] = "abcdefg"; // Replace abcdefg with your model name, eg. onnx_model_md5
    
    // Create an inference session using the Vitis AI execution provider
    session_options.AppendExecutionProvider("VitisAI", options);
    
    auto session = Ort::Experimental::Session(env, model_name, session_options);
    
    auto input_shapes = session.GetInputShapes();
    // preprocess input data
    // ...
    
    // Create input tensors and populate input data
    std::vector<Ort::Value> input_tensors;
    input_tensors.push_back(Ort::Experimental::Value::CreateTensor<float>(
    input_data.data(), input_data.size(), input_shapes[0]));
    
    auto output_tensors = session.Run(session.GetInputNames(), input_tensors,
    session.GetOutputNames());
    // postprocess output data
    // ...

    要利用 Python API,请使用以下示例作为参考:

    
    import onnxruntime
    
    # Add other imports
    # ...
    
    # Load inputs and do preprocessing
    # ...
    
    # Create an inference session using the Vitis-AI execution provider
    
    session = onnxruntime.InferenceSession(
    '[model_file].onnx',
    providers=["VitisAIExecutionProvider"],
    provider_options=[{"config_file":"/etc/vaip_config.json"}])
    
    input_shape = session.get_inputs()[0].shape
    input_name = session.get_inputs()[0].name
    
    # Load inputs and do preprocessing by input_shape
    input_data = [...]
    result = session.run([], {input_name: input_data})
  4. 创建 build.sh 文件,或者从 Vitis AI Library ONNX 示例复制该文件并对其进行修改。然后,构建该程序:
    result=0 && pkg-config --list-all | grep opencv4 && result=1
    if [ $result -eq 1 ]; then
    	OPENCV_FLAGS=$(pkg-config --cflags --libs-only-L opencv4)
    else
    	OPENCV_FLAGS=$(pkg-config --cflags --libs-only-L opencv)
    fi
    
    lib_x=" -lglog -lunilog -lvitis_ai_library-xnnpp -lvitis_ai_library-model_config -lprotobuf -lxrt_core -lvart-xrt-device-handle -lvaip-core -lxcompiler-core -labsl_city -labsl_low_level_hash -lvart-dpu-controller -lxir -lvart-util -ltarget-factory -ljson-c" 
    lib_onnx=" -lonnxruntime" 
    lib_opencv=" -lopencv_videoio -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc -lopencv_core " 
    
    if [[ "$CXX"  == *"sysroot"* ]];then
     inc_x="-I=/usr/include/onnxruntime -I=/install/Release/include/onnxruntime -I=/install/Release/include -I=/usr/include/xrt"
     link_x="  -L=/install/Release/lib"
    else
     inc_x=" -I/usr/include/onnxruntime  -I/usr/include/xrt"
     link_x="  "
    fi
    
    name=$(basename $PWD)
    
    CXX=${CXX:-g++}
    $CXX -O2 -fno-inline -I. \
     ${inc_x} \
     ${link_x} \
     -o ${name}_onnx -std=c++17 \
     $PWD/${name}_onnx.cpp \
     ${OPENCV_FLAGS} \
     ${lib_opencv} \
     ${lib_x} \
     ${lib_onnx} 
  5. 将可执行程序和已量化的 ONNX 模型复制到目标。然后,运行该程序。
    注释: 对于 ONNX 模型部署,输入模型是已量化的 ONNX 模型。如果环境变量 WITH_XCOMPILER 设为 on,那么您运行该程序时,它会首先在线执行模型编译。模型编译可能需要一段时间。