Vitis AI 5.1 NPU多实例支持

作者:Sun Grace,AMD工程师;文章来源:AMD开发者社区

简介

Vitis AI 5.1 是首个支持NPU的 Vitis AI 公开版本。与之前发布的Vitis AI相比,神经处理单元 (NPU) 取代了深度学习处理单元 (DPU) 架构。此版本为 Beta 版,面向 Versal AI Edge 系列自适应 SoC。正式版计划于 2026 年第一季度发布。

Vitis AI 5.1的安装包中提供了基于VEK280 platform的X+ML 参考设计,其中“X”指的是硬件加速的预处理任务(包括调整大小、色彩空间转换、归一化和裁剪),“ML”指的是在神经处理单元 (NPU) 上运行的推理任务。参考设计的路径位于:

<path-to-extracted-vitis-ai-5.1.tar>/Vitis-AI/examples/reference_design/vek280/

参考设计编译中,默认集成的NPU IP配置为VE2802_NPU_IP_O00_A304_M3。IP命名遵循以下规则:

[Target]_NPU_IP_O[AIE_Offset]_A[AIE_number]_M[DDRS_number]

其中:

Target:生成 IP(AIE/RTL 代码)的芯片

AIE_Offset:分区分配起始的最左侧 AIE 列

AIE_number:使用的 AIE 数量

DDRS_number:IP 所需的外部存储器数量

Vitis AI 5.1支持实例化多个NPU IP,从而在不同的 NPU IP 上并发执行多个模型,提高硬件利用率和效率。本文介绍如何在参考设计中集成多个NPU IP,编译及执行多个模型。

多实例NPU参考设计的构建

构建多实例NPU参考设计之前的准备工作与构建默认参考设计相同:

  1. 下载Vitis AI 源代码 (vitis-ai-5.1.tar)

  2. 下载VEK280 XSCT BSP v2025.1

  3. 获取 NPU IP license:如果没有license,跑参考设计的Vivado综合时会报错。NPU IP license是免费的,但需要申请并安装。请联系vitis_ai@amd.com ,或者您的AMD FAE获取license。当收到主题为“Xilinx Download Invitation for Account Access”的邮件后,请登录http://www.xilinx.com/getlicense,您会在下拉菜单中看到新增的 VITIS AI Early Access IP 账户,如下图所示。可以使用此账户生成并安装 AIE-ML NPU IP license。

1.png

参考设计的编译是基于<path-to-extracted-vitis-ai-5.1.tar>/Vitis-AI/examples/reference_design/vek280/Makefile,在make之前,需要在命令行启用多个NPU IP,步骤如下:

1.解压下载的vitis-ai-5.1.tar,cd <path-to-extracted-vitis-ai-5.1.tar>/Vitis-AI/

2. source npu_ip/settings.sh LIST,此命令列出所有支持的NPU IP:

2.png

可在source npu_ip/settings.sh后接具体的IP名启用IP,缺省情况下就启用VE2802_NPU_IP_O00_A304_M3。

3. 多实例的示例中,我们启用以下两个NPU IP:

  • VE2802_NPU_IP_O00_A128_M3

  • VE2802_NPU_IP_O16_A080_M3

这里需要注意的是:多实例 NPU 支持对 IP 的选择有限制。由于 AIE(GMIO)和 PL(LUT/FF/NMU)的资源数量以及 DDR 带宽的限制,使用过多的 IP 在实际中并不可行。

source npu_ip/settings.sh VE2802_NPU_IP_O00_A128_M3 VE2802_NPU_IP_O16_A080_M3

运行完再重复步骤2 LIST的结果如下

3.png

此时在命令行echo $NPU_IP2,其变量值为VE2802_NPU_IP_O16_A080_M3,与second IP对应。

多个NPU IP的集成需要在默认参考设计脚本的基础上做一些改动。官方提供的参考设计已经包含了基于上述启用的两个NPU IP的更改,方便用户参考和运行。大致思路是判断$NPU_IP2是否设置,如有则进行额外的操作。改动如下:

$VAISW_HOME/examples/reference_design/vek280/vek280_platform/sw/create_petalinux.sh

拷贝不同的设备树文件

4.png

拷贝NPU实例相关联的FPGA比特流信息文件

5.png这里的$VAISW_SNAPSHOT_TIMESTAMP和$VAISW_SNAPSHOT_TIMESTAMP2在上文启用了两个NPU IP后自动设置,

6.png

分别对应安装路径中npu_ip中特定的fpga_info_*.txt:

$VAISW_HOME/npu_ip/VE2802_NPU_IP_O00_A128_M3/fpga_info_96086F78.txt

$VAISW_HOME/npu_ip/VE2802_NPU_IP_O16_A080_M3/fpga_info_96081A6B.txt

$VAISW_HOME/examples/reference_design/vek280/vitis_prj/kernels/npu_vss/Makefile

拷贝NPU IP AIE kernel相关的文件以及Vitis Subsystem Component (VSS),将 NPU IP 实例特定的 PL NMU 布局合并到一个 tcl 文件中,并将所有 IP 配置合并到一个统一的 system.cfg 文件中。

7.png

$VAISW_HOME/examples/reference_design/vek280/vitis-prj/Makefile

在使用 Vitis 工具链 (v++) 进行link和package时,确保包含 每个NPU IP 实例特有的文件,为VSS、libadf、snapshot、fpga_info 文件等使用唯一的名称,以避免发生冲突。

8.JPG

介绍完上述必要的改动后,让我们回头再来看看参考设计根目录下Makefile里的snapshot生成部分。

$VAISW_HOME/examples/reference_design/vek280/Makefile

9.png

在SD 卡编译期间,首先会在docker环境为目标 NPU IP 生成ResNet50 和 ResNet101 模型各自的snapshot。

如果你在外部docker环境已经生成了待部署模型的snapshot,或者目前只关注参考设计vek280的编译流程,可以设置 SKIP_SNAPSHOT=1 选项在 SD 卡生成期间跳过此步骤,具体命令请参考下文。

构建包含VE2802_NPU_IP_O00_A128_M3和VE2802_NPU_IP_O16_A080_M3两个NPU IP的参考设计所需的步骤如下:

cd <path-to-extracted-vitis-ai-5.1.tar>/Vitis-AI/

source npu_ip/settings.sh VE2802_NPU_IP_O00_A128_M3 VE2802_NPU_IP_O16_A080_M3

source <path_to_Vitis>/2025.1.1/Vitis/settings64.sh

source <path_to_petalinux-v2025.1>/tool/petalinux-v2025.1-final/settings.sh

cd examples/reference_design/vek280

SKIP_SNAPSHOT=1 make all BSP_PATH=<path_to_petalinux-v2025.1>/bsp/xsct/xilinx-vek280-xsct-v2025.1-final.bsp

最后一条make语句如果移除SKIP_SNAPSHOT=1,则会在当前路径生成4个snapshot文件夹,包含Vitis AI对模型的编译结果。

10.png

这些snapshot都会被一并打包至board image。

如果你的运行路径为NFS,在petalinux构建过程中会遇到类似以下的错误:

11.png

解决的方式是修改 

$VAISW_HOME/examples/reference_design/vek280/vek280_platform/sw/create_petalinux.sh,把tmpdir改成本地磁盘空间。

例如,

tmpdir="$ABS_PATH/tmp/plnx_tmp"

-->

tmpdir="/tmp"

/tmp为占有本地存储空间的大容量目录。

上述命令成功运行后,会生成VE2802_NPU_IP_O00_A128_M3__O16_A080_M3_sd_card.img,位于当前路径的output文件夹下。可用于烧录SD卡,启动VEK280。

至此,参考设计的构建部分已完成,接下来是为每个NPU IP编译待执行的模型生成snapshot。不同的 NPU IP会使用不同的资源和 AIE 地址,因此,即使在不同的 IP上使用相同的模型,也需要为每个 IP 生成一个snapshot。

生成snapshot的步骤在此不再赘述,本文主要以参考设计默认生成的ResNet50 和ResNet101 snapshot为例上板执行。

使用多个NPU IP执行多个模型

VEK280目标板的设置请参考:https://vitisai.docs.amd.com/en/latest/docs/install/hardware.html#vek280-target-board-setup

确认SD卡烧录的为VE2802_NPU_IP_O00_A128_M3__O16_A080_M3_sd_card.img。

附件的imagenet需要一并拷贝至SD卡,或者在板子启动后通过ethernet口用scp远程拷贝至系统。

见附件

依次执行

cd /run/media/mmcblk0p1

unzip imagenet.zip

source /etc/vai.sh

vart_ml_demo --imgPath ./imagenet/ILSVRC2012_img_val/ --snapshot snapshot.VE2802_NPU_IP_O00_A128_M3.resnet50.TF/+snapshot.VE2802_NPU_IP_O16_A080_M3.resnet50.TF --labels /etc/vai/labels/labels --goldFile ./imagenet/ILSVRC_2012_val_GroundTruth_10p.txt --nbImages 1

这里的vart_ml_demo是VART Runner C++ 应用程序,编译参考设计时已经包含于board image中。C代码源文件的位置为:

$VAISW_HOME/src/vart_ml/demo/

vart_ml_demo基于 VART C++ API 实现,它包含了 ResNet50 的预处理和后处理以及 top1/top5 的计算。命令会输出分类的概率分数以及准确率摘要。稍作修改后,它也可能适用于其他模型。

对于自定义模型,您需要使用自己的预处理和后处理实现来定制此应用程序。另外,channelOrder 默认为 BGR,因为示例模型 (ResNet50) 使用 BGR 格式训练。您需要根据模型的训练格式更改它。

这里--snapshot选项我们指定了两个resnet50 snapshot,分别适配于两个NPU IP,值之间用“+”分隔符分隔。运行结果如下:

12.png

如果是采用预编译的resnet101 snapshot,需要修改标签文件。Image中自带的/etc/vai/labels/labels文件与提供的 resnet50 模型(1000 个类别)兼容,但与 resnet101 模型(1001 个类别)不完全兼容。

要使标签文件适用于提供的 resnet101 模型,可以复制 /etc/vai/labels/labels 文件,并在文件顶部添加一行,将后面所有标签的偏移量加一,然后使用复制后的标签文件。

示例如下:

13.png

假设修改后的标签文件我们命名为labels_1001。vart_ml_demo的命令相应修改如下:

vart_ml_demo --imgPath ./imagenet/ILSVRC2012_img_val/ --snapshot snapshot.VE2802_NPU_IP_O00_A128_M3.resnet101.TF/+snapshot.VE2802_NPU_IP_O16_A080_M3.resnet101.TF --labels ./labels_1001 --goldFile ./imagenet/ILSVRC_2012_val_GroundTruth_10p.txt --nbImages 1

运行结果与前类似:

14.png

还可以使用image自带的 X+ML 应用程序 (x_plus_ml_app) 在多个 NPU 上执行snapshot。源代码在安装包中的位置:

$VAISW_HOME/examples/x_plus_ml/

命令行用法示例:

Single snapshot execution :- "x_plus_ml_app -i dog.jpg -c /etc/vai/json-config/yolox_pl.json -s snapshot.yolox.0408 -l 3"

Multi snapshots execution :- "x_plus_ml_app -i dog.jpg+dog.jpg -c /etc/vai/json-config/yolox_pl.json+/etc/vai/json-config/yolox_pl.json -s snapshot.yolox.0408+snapshot.yolox.0408 -l 3+3"

两个snapshot,输入文件,配置文件等选项如有多个,均用+分隔符隔开。

下面以resnet50和yolox模型为例,如何用x_plus_ml_app分别在两个NPU IP上执行。

先在host端生成docker demo里的yolox snapshot。

source npu_ip/settings.sh VE2802_NPU_IP_O16_A080_M3

./docker/run.bash --acceptLicense -- /bin/bash -c "source npu_ip/settings.sh && cd /home/demo/YOLOX && VAISW_SNAPSHOT_DUMPIOS=5 VAISW_SNAPSHOT_DIRECTORY=$PWD/snapshot.VE2802_NPU_IP_O16_A080_M3.yolox VAISW_RUNOPTIMIZATION_DDRSHAPE=N_C_H_W_c VAISW_QUANTIZATION_NBIMAGES=1 ./run assets/dog.jpg m --save_result"

将生成的snapshot.VE2802_NPU_IP_O16_A080_M3.yolox文件夹以及docker中的/home/demo/YOLOX/assets/dog.jpg拷贝至目标板。

上板运行:

source /etc/vai.sh

export VAISW_RUNSESSION_SUMMARY=all

x_plus_ml_app -i dog.jpg+dog.jpg -s snapshot.VE2802_NPU_IP_O00_A128_M3.resnet50.TF/+snapshot.VE2802_NPU_IP_O16_A080_M3.yolox -c /etc/vai/json-config/resnet50.json+/etc/vai/json-config/yolox_pl.json -l 3+3 -m 4+4

运行结果如下,设置VAISW_RUNSESSION_SUMMARY可以打印出性能统计。

15.png

16.png

总结

本文阐述了如何构建包含多个NPU IP实例的VEK280参考设计,及如何用vart_ml_demo和x_plus_ml_app应用程序执行多个模型。在此流程的基础上,用户可定制自己的应用程序,实现并行处理并最大限度地提高效率,从而更容易在同一平台上部署多模型工作负载。