摘要:本文详细记录了在 Linux 主机上使用 Qualcomm SNPE SDK 2.21 部署 VGG16 ONNX 模型的完整流程,涵盖环境搭建、依赖安装、模型下载与转换、主机 CPU 推理验证、ARM64 交叉编译 C++ Sample、板端部署运行以及输出结果验证等九个步骤。文章还针对官方案例未预设 Python 环境的问题,提供了多种虚拟环境配置方案,帮助读者从零开始跑通 SNPE VGG 案例。
一、相关文档入口
这次 VGG 案例主要看这些文档:
| 主题 | 文档 |
|---|---|
| SDK 环境 | docs/SNPE/html/general/setup.html |
| 教程资源准备 | docs/SNPE/html/general/tutorial_setup.html |
| VGG ONNX 教程 | docs/SNPE/html/general/tutorial_onnx.html |
| ONNX 转 DLC 工具 | docs/SNPE/html/general/tools_model_conversion.html |
推理工具snpe-net-run | docs/SNPE/html/general/tools_execution.html |
| C++ Sample 交叉编译 | docs/SNPE/html/general/cplus_plus_tutorial.html |
VGG 相关脚本在:
${SNPE_ROOT}/examples/Models/VGG/scripts/核心脚本:
setup_VGG.py create_VGG_raws.py create_file_list.py show_vgg_classifications.pyC++ 测试代码在:
${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode/jni/main.cpp二、Linux 主机安装依赖
SNPE 2.21 的check-python-dependency明确要求:
- Python
3.6或3.8 - 必须在 virtualenv/conda 环境中运行
- 推荐 Python 3.8
如果你用uv,推荐:
cd /path/to/snpe_2.21 uv python install 3.8 uv venv .venv-snpe --python 3.8 source .venv-snpe/bin/activate如果不用uv:
sudo apt update sudo apt install -y python3.8 python3.8-venv python3.8-dev python3-pip wget make build-essential cd /path/to/snpe_2.21 python3.8 -m venv .venv-snpe source .venv-snpe/bin/activate设置 SNPE 环境:(#XXX是snpe_2.21的本机路径,自行替换正确路径)
后续执行模型转换后,直接在onnx 模型路径下执行命令就行。
export SNPE_ROOT=/XXX/snpe_2.21 source ${SNPE_ROOT}/bin/envsetup.sh之前你遇到过Permission denied,所以这里用python3直接执行检查脚本:
python3 ${SNPE_ROOT}/bin/check-python-dependencyVGG 最小依赖是:
python3 -m pip install numpy pillow scipy onnx但更推荐跑上面的check-python-dependency,它会按 SDK 测试过的版本安装完整依赖。
三、下载 VGG 模型和数据
官方 VGG 脚本会下载三类资源:
vgg16.onnx synset.txt kitten.jpg来源在setup_VGG.py里写死:
https://s3.amazonaws.com/onnx-model-zoo/vgg/vgg16/vgg16.onnx https://s3.amazonaws.com/onnx-model-zoo/synset.txt https://s3.amazonaws.com/model-server/inputs/kitten.jpg执行:
cd ${SNPE_ROOT}/examples/Models/VGG python3 scripts/setup_VGG.py -a ./onnx -d脚本会自动完成:
1. 下载 vgg16.onnx、synset.txt、kitten.jpg 2. 生成 data/cropped/*.raw 3. 生成 data/cropped/raw_list.txt 4. 生成 dlc/vgg16.dlc注意跑测py需要在创建的uv环境下,官方案例没有设定环境,需要认为导入:
方法一:激活虚拟环境(推荐)
# 激活虚拟环境 source /home/XXX/My_Snpe_Project/snpe_2.21/.venv-snpe38/bin/activate 在虚拟环境中安装 onnx pip install onnx 验证 python -c "import onnx; print(onnx.version)"方法二:查看当前用的是哪个 Python
which python3 python3 --version 确认 onnx 安装位置 ls /home/XXX/.local/lib/python3.8/site-packages/ | grep onnx 临时把 user site-packages 加入 PYTHONPATH export PYTHONPATH=/home/quectel/.local/lib/python3.8/site-packages:$PYTHONPATH python3 -c "import onnx; print(onnx.version)"将user site-packages 永久加入 PYTHONPATH方法:
方法一:在虚拟环境中安装(最推荐)
既然你已经有一个.venv-snpe38虚拟环境,直接在虚拟环境里装onnx,一劳永逸:
source /home/XXX/My_Snpe_Project/snpe_2.21/.venv-snpe38/bin/activate pip install onnx之后只要激活该虚拟环境,onnx就能直接使用,无需额外设置。
方法二:加到~/.bashrc(全局生效)
如果你希望所有终端都自动包含 user site-packages:
echo 'export PYTHONPATH=/home/XXX/.local/lib/python3.8/site-packages:$PYTHONPATH' >> ~/.bashrc source ~/.bashrc方法三:修改 SNPE 的envsetup.sh(仅在 source 时生效)
如果你希望只在 SNPE 环境下生效,修改envsetup.sh:
echo 'export PYTHONPATH=/home/XXX/.local/lib/python3.8/site-packages:$PYTHONPATH' >> /home/XXX/My_Snpe_Project/snpe_2.21/bin/envsetup.sh方法三:直接在虚拟环境中安装(如果已有虚拟环境)
# 用虚拟环境的 pip 安装 /home/XXX/My_Snpe_Project/snpe_2.21/.venv-snpe38/bin/pip install onnx 用虚拟环境的 python 运行 /home/XXX/My_Snpe_Project/snpe_2.21/.venv-snpe38/bin/python -c "import onnx; print(onnx.version)"如果网络不通,也可以手动下载:
mkdir -p ${SNPE_ROOT}/examples/Models/VGG/onnx cd ${SNPE_ROOT}/examples/Models/VGG/onnx wget -N https://s3.amazonaws.com/onnx-model-zoo/vgg/vgg16/vgg16.onnx wget -N https://s3.amazonaws.com/onnx-model-zoo/synset.txt wget -N https://s3.amazonaws.com/model-server/inputs/kitten.jpg然后执行:
cd ${SNPE_ROOT}/examples/Models/VGG python3 scripts/create_VGG_raws.py -i onnx -d data/cropped python3 scripts/create_file_list.py -i data/cropped -o data/cropped/raw_list.txt -e "*.raw" python3 scripts/create_file_list.py -i data/cropped -o data/raw_list.txt -e "*.raw" -r cp onnx/synset.txt data/四、模型转换 ONNX → DLC
如果不用setup_VGG.py自动转换,可以手动执行:
cd ${SNPE_ROOT}/examples/Models/VGG mkdir -p dlc snpe-onnx-to-dlc --input_network onnx/vgg16.onnx --output_path dlc/vgg16.dlc或 在根目录下运行代码注意路径问题
cd ${SNPE_ROOT}/examples/Models/VGG mkdir -p dlc python3 ./bin/x86_64-linux-clange/snpe-onnx-to-dlc --input_network ./examples/Models/VGG/onnx/vgg16.onnx --output_path ./examples/Models/VGG/dlc/vgg16.dlc检查 DLC:
snpe-dlc-info -i dlc/vgg16.dlc或 在根目录下运行代码注意路径问题
python3 ./bin/x86_64-linux-clang/snpe-dlc-info -i ./examples/Models/VGG/dlc/vgg16.dlc主机上先跑一次 CPU 推理验证: (在根目录下运行代码注意路径问题)
cd ${SNPE_ROOT}/examples/Models/VGG/data/cropped snpe-net-run --input_list raw_list.txt --container ../../dlc/vgg16.dlc --output_dir ../../output注意:
snpe-net-run不是 Python 脚本,是高通 SNPE 编译出来的二进制可执行文件,你用python3去运行二进制文件,必然报编码语法错误。
补充常见前置操作
- 赋予执行权限(第一次运行必做)
# 替换成你自己的SNPE根目录 source ${SNPE_ROOT}/bin/envsetup.sh x86_64-linux-clang- 加载 SNPE 环境变量(否则会报库找不到)
chmod +x ./bin/x86_64-linux-clang/snpe-net-run查看分类结果:
cd ${SNPE_ROOT}/examples/Models/VGG python3 scripts/show_vgg_classifications.py -i data/cropped/raw_list.txt -o output -l data/synset.txt成功时会输出 top-5 分类,例如 kitten 相关类别。
举例 输入: python3 ./examples/Models/VGG/scripts/show_vgg_classifications.py -i ./examples/M odels/VGG/data/cropped/raw_list.txt -o ./examples/Models/VGG/output/ -l ./examples/Models/VGG/data/synset.txt输出: Classification results probability=0.339871 ; class=n02123045 tabby, tabby cat probability=0.329623 ; class=n02124075 Egyptian cat probability=0.299326 ; class=n02123159 tiger cat probability=0.021479 ; class=n02127052 lynx, catamount五、Linux 上交叉编译 ARM64 C++ Sample
SNPE 已提供 Makefile:
${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode/Makefile.aarch64-oe-linux-gcc11.2 ${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode/Makefile.aarch64-ubuntu-gcc9.4如果你的板子是 Yocto / LE Linux,推荐:
export SNPE_TARGET_ARCH=aarch64-oe-linux-gcc11.2交叉工具链路径示例:
export AARCH64_LINUX_OE_GCC_112=/path/to/qcom-esdk编译:
cd ${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode make clean -f Makefile.aarch64-oe-linux-gcc11.2 make -f Makefile.aarch64-oe-linux-gcc11.2如果 Makefile 默认路径不匹配,直接传CXX:
make CXX="/path/to/esdk/sysroots/x86_64-qtisdk-linux/usr/bin/aarch64-oe-linux/aarch64-oe-linux-g++ --sysroot=/path/to/esdk/sysroots/armv8a-oe-linux" \ -f Makefile.aarch64-oe-linux-gcc11.2产物:
${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode/obj/local/aarch64-oe-linux-gcc11.2/snpe-sample如果你的目标板是 Ubuntu ARM64:
export SNPE_TARGET_ARCH=aarch64-ubuntu-gcc9.4 export AARCH64_UBUNTU_GCC_94=/path/to/aarch64-ubuntu-toolchain cd ${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode make -f Makefile.aarch64-ubuntu-gcc9.4六、拷贝到 ARM Linux 设备
假设板子 IP 是192.168.1.100,用户名是root:
export SNPE_TARGET_ARCH=aarch64-oe-linux-gcc11.2 export TARGET_IP=192.168.1.100 export TARGET_USER=root export TARGET_DIR=/data/local/tmp/snpe_vgg ssh ${TARGET_USER}@${TARGET_IP} "mkdir -p ${TARGET_DIR}/bin ${TARGET_DIR}/lib ${TARGET_DIR}/model ${TARGET_DIR}/data/cropped ${TARGET_DIR}/output"拷贝 SNPE 运行库和工具:
scp ${SNPE_ROOT}/bin/${SNPE_TARGET_ARCH}/snpe-net-run \ ${TARGET_USER}@${TARGET_IP}:${TARGET_DIR}/bin/ scp ${SNPE_ROOT}/lib/${SNPE_TARGET_ARCH}/*.so ${TARGET_USER}@${TARGET_IP}:${TARGET_DIR}/lib/拷贝交叉编译的 sample:
scp ${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode/obj/local/${SNPE_TARGET_ARCH}/snpe-sample \ ${TARGET_USER}@${TARGET_IP}:${TARGET_DIR}/bin/拷贝 VGG 模型和输入:
scp ${SNPE_ROOT}/examples/Models/VGG/dlc/vgg16.dlc \ ${TARGET_USER}@${TARGET_IP}:${TARGET_DIR}/model/ scp ${SNPE_ROOT}/examples/Models/VGG/data/cropped/*.raw ${TARGET_USER}@${TARGET_IP}:${TARGET_DIR}/data/cropped/ scp ${SNPE_ROOT}/examples/Models/VGG/data/cropped/raw_list.txt ${TARGET_USER}@${TARGET_IP}:${TARGET_DIR}/data/cropped/ scp ${SNPE_ROOT}/examples/Models/VGG/data/synset.txt ${TARGET_USER}@${TARGET_IP}:${TARGET_DIR}/data/七、ARM 设备上运行 snpe-net-run
登录板子:
ssh root@192.168.1.100设置环境:
export TARGET_DIR=/data/local/tmp/snpe_vgg export LD_LIBRARY_PATH=${TARGET_DIR}/lib:${LD_LIBRARY_PATH} export PATH=${TARGET_DIR}/bin:${PATH}测试 SNPE 工具:
snpe-net-run -h运行 VGG:
cd ${TARGET_DIR} snpe-net-run --input_list data/cropped/raw_list.txt --container model/vgg16.dlc --output_dir output输出文件一般是:
${TARGET_DIR}/output/Result_0/vgg0_dense2_fwd.raw八、ARM 设备上运行交叉编译 sample
cd ${TARGET_DIR} snpe-sample -b ITENSOR -d model/vgg16.dlc -i data/cropped/raw_list.txt -o output_sample -r cpu参数说明:
-b ITENSOR 使用 ITensor 输入输出 -d vgg16.dlc DLC 模型 -i raw_list.txt 输入 raw 列表 -o output_sample 输出目录 -r cpu CPU runtime如果要试 GPU/DSP:
snpe-sample -b ITENSOR -d model/vgg16.dlc -i data/cropped/raw_list.txt -o output_gpu -r gpu snpe-sample -b ITENSOR -d model/vgg16.dlc -i data/cropped/raw_list.txt -o output_dsp -r dspDSP 还需要额外推送 Hexagon 库并设置ADSP_LIBRARY_PATH,先跑 CPU 最稳。
九、测试代码:拉回输出并验证 top-5
在主机上拉回板端输出:
mkdir -p ${SNPE_ROOT}/examples/Models/VGG/arm_output scp -r root@192.168.1.100:/data/local/tmp/snpe_vgg/output ${SNPE_ROOT}/examples/Models/VGG/arm_output/用官方测试脚本验证:
cd ${SNPE_ROOT}/examples/Models/VGG python3 scripts/show_vgg_classifications.py -i data/cropped/raw_list.txt -o arm_output/output -l data/synset.txt如果你想要一个更小的独立测试脚本,可保存为verify_vgg_output.py:
import argparse import numpy as np from scipy.special import softmax parser = argparse.ArgumentParser() parser.add_argument("--raw", required=True) parser.add_argument("--labels", required=True) args = parser.parse_args() logits = np.fromfile(args.raw, dtype=np.float32) if logits.size != 1000: raise RuntimeError(f"Expected 1000 outputs, got {logits.size}") with open(args.labels, "r") as f: labels = [x.strip() for x in f] probs = softmax(logits) top5 = np.argsort(probs)[::-1][:5] for i in top5: print(f"{probs[i]:.6f} {labels[i]}")运行:
python3 verify_vgg_output.py \ --raw ${SNPE_ROOT}/examples/Models/VGG/arm_output/output/Result_0/vgg0_dense2_fwd.raw \ --labels ${SNPE_ROOT}/examples/Models/VGG/data/synset.txt最短跑通路线
source .venv-snpe/bin/activate export SNPE_ROOT=/path/to/snpe_2.21 source ${SNPE_ROOT}/bin/envsetup.sh python3 ${SNPE_ROOT}/bin/check-python-dependency cd ${SNPE_ROOT}/examples/Models/VGG python3 scripts/setup_VGG.py -a ./onnx -d cd data/cropped snpe-net-run --input_list raw_list.txt --container ../../dlc/vgg16.dlc --output_dir ../../output cd ${SNPE_ROOT}/examples/Models/VGG python3 scripts/show_vgg_classifications.py -i data/cropped/raw_list.txt -o output -l data/synset.txt