1. 环境准备:认识SNPE与你的开发机

如果你手头有一台搭载了高通骁龙芯片的设备,比如手机、平板或者开发板,并且想在上面跑一跑AI模型,感受一下端侧推理的速度,那么SNPE就是你绕不开的工具。SNPE,全称Snapdragon Neural Processing Engine,你可以把它理解成高通为自家骁龙平台量身打造的一个“AI模型加速引擎”。它的作用,就是把你在PC上训练好的那些模型(比如PyTorch、TensorFlow或者ONNX格式的),转换、优化,最终部署到骁龙芯片的NPU、GPU或者DSP上高效运行。这感觉,有点像NVIDIA的TensorRT,只不过战场从显卡换到了手机芯片。

在开始动手之前,你得先搞清楚两件事:你的开发环境和你的目标设备。这篇文章主要聚焦在Linux开发环境的搭建上,这也是最主流、问题最集中的场景。我强烈建议你使用一台Ubuntu 20.04或22.04的机器,无论是实体机、虚拟机还是云服务器。别用太老的系统,比如Ubuntu 18.04,后期依赖库的兼容性问题能把你折腾得够呛。我自己就踩过这个坑,在18.04上为了一个库版本折腾了半天,最后发现还不如重装系统来得快。

硬件方面,你的开发机不需要有骁龙芯片,SNPE的工具链是运行在x86的Linux上的,它的任务是准备模型和生成部署包。最终运行模型的是你的骁龙设备(比如用adb连接的一台安卓手机)。所以,确保你的开发机有足够的磁盘空间(建议至少预留20GB),并且网络通畅,因为我们需要下载不少东西。

最后,给自己准备好一个干净的终端窗口,以及一颗不怕报错的心。配置环境这种事,一次成功是运气,边查边改才是常态。接下来,我们就从安装高通官方的“应用商店”开始。

2. 安装QPM:获取SNPE的“官方应用商店”

以前安装SNPE,可能还能找到直接下载的压缩包,但现在高通把SNPE的发行都收归到自家的包管理工具QPM(Qualcomm Package Manager)下了。这有点像Ubuntu的apt或者Python的pip,你得先把这个“应用商店”装好,才能从里面安装SNPE。

第一步,下载QPM安装包。 打开浏览器,访问高通开发者网络的QPM页面。你需要找到适用于Linux x86_64的QPM安装包。这个包的版本号可能会更新,比如我写这篇文章时,最新的稳定版是QualcommPackageManager3.3.0.88.3.Linux-x86.deb。如果你看到更新的版本,用新的就行,基本操作是一样的。

第二步,使用dpkg命令安装。 下载完成后,打开终端,切换到下载目录。安装命令非常简单:

sudo dpkg -i QualcommPackageManager3.3.0.88.3.Linux-x86.deb

输入密码后,安装过程通常很快。如果系统提示缺少某些依赖,比如libfuse2,你可以用apt来修复安装:

sudo apt --fix-broken install

这条命令会自动安装缺失的依赖,然后再重新配置QPM。

第三步,验证安装。 安装完成后,在终端里输入qpm-cli --version。如果能看到版本号输出,比如3.3.0.88.3,那就恭喜你,第一步成功了。如果提示命令未找到,可以尝试重新打开一个终端窗口,或者手动执行一下source /etc/profile让环境变量生效。

这里有个小经验分享:我建议把QPM安装过程中所有输出到屏幕的日志都仔细看一遍,特别是关于安装路径的提示。默认情况下,QPM本身会安装到/opt/qualcomm/qpm目录下,而后续通过它安装的SDK(比如SNPE)会放在/opt/qcom目录里。知道这些路径,后面排查问题会方便很多。

3. 安装SNPE SDK核心工具链

有了QPM,我们就能“购买”并安装SNPE这个“软件”了。这个过程其实是从高通服务器下载一个.qik格式的归档文件,然后解压安装。

第一步,找到并下载SNPE的.qik文件。 你需要再次访问高通开发者网站,在工具列表里找到“Qualcomm Neural Processing SDK”。点击进入后,你会看到一个下载按钮,获取到一个后缀为.qik的文件,例如qualcomm_neural_processing_sdk.2.16.0.231029.Linux-AnyCPU.qik。这里版本选择有个大坑,我强烈建议你先别急着用最新的版本。我一开始图新鲜,直接装了当时最新的2.22版本,结果在后续转换模型时,疯狂报错libpython3.10.so.1.0找不到。查了半天发现是SDK内部对Python共享库的链接有问题。后来我回退到2.16.0.231029这个版本,就一路顺畅了。所以,除非你有明确需求,否则建议先使用这个经过更多人验证的稳定版本。

第二步,使用QPM命令行工具安装。 把下载好的.qik文件放到你方便操作的目录,比如~/Downloads。然后在终端中执行:

qpm-cli --extract qualcomm_neural_processing_sdk.2.16.0.231029.Linux-AnyCPU.qik

执行这个命令后,QPM会启动一个交互式安装流程。它会先让你阅读并接受一份许可协议,输入y继续。接着,它会检查系统环境、依赖,并开始解压文件。安装过程会在终端打印详细的日志。

请你务必盯紧安装日志中的这一行:

[Info] : SUCCESS: Installed qualcomm_neural_processing_sdk.Core at /opt/qcom/aistack/snpe/2.16.0.231029

这行日志告诉了你SNPE SDK被安装到的绝对路径。请把这个路径记下来,后面每一步几乎都要用到它。我的是/opt/qcom/aistack/snpe/2.16.0.231029,你的应该类似,可能版本号稍有不同。如果安装中途报错,大概率是缺少某些系统依赖,比如libxml2或者unzip,根据错误提示用sudo apt install安装即可。

4. 配置系统与Python依赖环境

SDK安装好了,但它还不是一个“开箱即用”的状态。我们需要配置系统环境,让它能找到SNPE的命令和库,同时还要准备好Python转换脚本所需的环境。

4.1 检查并安装Linux系统依赖

SNPE提供了一個很方便的脚本来检查你的Linux系统是否缺少必要的依赖库。进入你刚才记下的SNPE安装目录下的bin文件夹:

cd /opt/qcom/aistack/snpe/2.16.0.231029/bin
bash check-linux-dependency.sh

运行这个脚本,它会自动检查。如果所有依赖都满足,你会看到成功的提示。如果发现有缺失的包,比如libgstreamer、libpng等,脚本会给出明确的apt安装命令,你只需要复制粘贴执行即可。

这里可能会遇到一个“坑”:脚本可能会尝试安装或更新Node.js。如果你的网络访问国外源比较慢,这一步会卡住很久。你可以通过设置环境变量来使用国内的镜像加速,像这样:

NODE_MIRROR=https://mirrors.bfsu.edu.cn/nodejs-release/ bash check-linux-dependency.sh

4.2 配置Python转换环境

SNPE的模型转换工具(如snpe-onnx-to-dlc)很多是用Python写的,所以需要一个独立的Python环境。官方推荐使用Python 3.6到3.8,与PyTorch等框架搭配。我习惯用Conda来管理,干净又省心。

首先,创建一个新的Conda环境:

conda create -n snpe_env python=3.8 -y
conda activate snpe_env

然后,安装PyTorch。注意,我们这里安装的PyTorch是给模型转换用的,运行在开发机上,所以选择CPU版本就够了,安装速度也快。

conda install pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cpuonly -c pytorch -y

版本选择1.11.0是一个比较兼容的版本。安装完成后,进入SNPE的bin目录,运行Python依赖检查脚本:

cd /opt/qcom/aistack/snpe/2.16.0.231029/bin
./check-python-dependency

这个脚本会检查当前激活的Python环境中是否缺少必要的包,比如onnx, numpy等。如果缺少,它会提示你用pip安装。你可以根据提示逐一安装。为了加速pip下载,可以临时换源:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

4.3 设置环境变量

这是最关键的一步,目的是让系统在任何位置都能识别SNPE的命令。SNPE提供了一个脚本来设置临时环境变量:

source /opt/qcom/aistack/snpe/2.16.0.231029/bin/envsetup.sh

执行后,你可以试试在终端输入snpe-然后按Tab键,如果能自动补全出一系列像snpe-onnx-to-dlc、snpe-net-run这样的命令,就说明成功了。

但这种方式是临时的,关闭终端就失效了。为了永久生效,我们需要把这条命令添加到shell的配置文件中。对于常用的bash,可以编辑用户目录下的.bashrc文件:

echo 'source /opt/qcom/aistack/snpe/2.16.0.231029/bin/envsetup.sh' >> ~/.bashrc

然后执行source ~/.bashrc让配置立即生效。这样,每次打开新的终端,SNPE的环境就已经准备好了。

5. 实战:从ONNX到DLC的模型转换

环境配好了,不跑个模型验证一下怎么行?我们用一个实际的例子,把经典的YOLO-NAS模型转换成SNPE专用的DLC格式。这个过程能帮你熟悉整个工作流,并暴露可能遇到的问题。

5.1 获取示例代码与模型

高通官方提供了一些示例工程,我们直接克隆下来:

git clone https://github.com/quic/qidk.git
cd qidk/Solutions/VisionSolution1-ObjectDetection-YoloNas

这个目录下有一个Jupyter Notebook文件GenerateDLC.ipynb。如果你习惯用Notebook,可以启动Jupyter来逐步运行。我这里为了清晰,把它里面的关键步骤拆解成命令行指令。

首先,安装模型所需的Python包(确保你在之前创建的snpe_env Conda环境中):

pip install super-gradients==3.1.2

5.2 下载预训练模型并导出ONNX

我们写一个Python脚本export_onnx.py来完成这件事:

import torch
from super_gradients.training import models
from super_gradients.common.object_names import Models

# 加载预训练的YOLO-NAS-S模型
print("Downloading YOLO-NAS model...")
model = models.get(Models.YOLO_NAS_S, pretrained_weights="coco")

# 将模型设置为评估模式,并准备转换
model.eval()
model.prep_model_for_conversion(input_size=[1, 3, 320, 320])

# 创建随机输入,并导出ONNX
dummy_input = torch.randn([1, 3, 320, 320], device="cpu")
torch.onnx.export(model, dummy_input, "yolo_nas_s.onnx", opset_version=11)
print("Model exported to yolo_nas_s.onnx")

运行这个脚本python export_onnx.py。你会看到一些关于许可证的警告,这是正常的,确认后模型就会开始下载并最终导出为一个yolo_nas_s.onnx文件。

5.3 使用SNPE转换ONNX至DLC

这是核心步骤,使用我们配置好的SNPE工具:

snpe-onnx-to-dlc -i yolo_nas_s.onnx -o yolo_nas_s.dlc

如果一切顺利,几秒钟后你就会在当前目录下看到生成的yolo_nas_s.dlc文件。这个.dlc文件就是可以被SNPE运行时加载并在骁龙设备上执行的模型格式。

但是,这一步极有可能出错! 我最常遇到的两个错误是:

  1. ImportError: libunwind.so.1: cannot open shared object file
  2. libpython3.10.so.1.0: cannot open shared object file

第一个错误是因为SNPE工具链动态链接了libunwind.so.1这个库,但你的系统里可能只有更高版本的,比如libunwind.so.8。解决方法不是重新安装,而是创建一个软链接“欺骗”一下系统:

# 首先查找libunwind.so.8的位置
sudo find /usr -name "libunwind.so.*"
# 通常它在/usr/lib/x86_64-linux-gnu/下
sudo ln -s /usr/lib/x86_64-linux-gnu/libunwind.so.8 /usr/lib/x86_64-linux-gnu/libunwind.so.1

第二个错误,如果出现,往往是因为你安装了不兼容的SNPE SDK版本(比如我之前说的2.22版)。最彻底的解决办法就是卸载当前版本,重新安装2.16.0.231029这个稳定版。这也印证了开头版本选择的重要性。

6. 进阶配置与调试技巧

走到这里,你已经成功搭建了环境并转换了第一个模型。但想在实际项目中游刃有余,还需要了解一些进阶知识和调试技巧。

理解SNPE的运行器(Runtime)选择:当你把DLC模型部署到手机后,需要选择在哪个硬件上运行。SNPE支持CPU、GPU、DSP和NPU。通过snpe-net-run工具可以指定运行时。例如,在连接了安卓设备的开发机上,你可以这样测试:

snpe-net-run --container your_model.dlc --input_list input_list.txt --use_gpu

这条命令会尝试在连接的安卓设备的GPU上运行模型。选择不同的运行时,性能差异会非常大。通常,NPU能效比最高,但算子支持可能有限;GPU吞吐量大;CPU最通用但能效低。你需要根据模型结构和实际设备来权衡。

模型量化与优化:直接从框架导出的浮点模型(FP32)在手机上运行可能比较慢。SNPE提供了模型量化工具,可以将FP32模型转换为INT8精度,在几乎不损失精度的情况下大幅提升速度并减少功耗。量化需要准备一些代表性的校准数据,过程稍复杂,但对于追求极致的应用来说是必由之路。

利用日志和工具排查问题:SNPE提供了详细的日志输出。在运行任何SNPE命令时,可以通过设置环境变量SNPE_LOG_LEVEL=DEBUG来获取最详细的日志信息,这对定位转换失败或推理错误的原因至关重要。另外,SNPE SDK中还包含一个叫做snpe-dlc-info的工具,可以用来查看DLC模型的内部信息,比如输入输出张量的名字和维度,这在编写推理代码时非常有用。

保持环境干净:我强烈建议为不同的项目创建独立的Conda环境。SNPE的Python依赖相对固定,如果你在一个环境里频繁升级各种包,很容易导致与SNPE工具链不兼容。把SNPE的环境当作一个“基础工具环境”,不要在里面做其他实验。

配置SNPE环境的过程,就像是在组装一个精密的仪器。每一步都有明确的指令,但偶尔会遇到螺丝对不上孔的情况(比如库版本冲突)。我的经验是,严格按照官方推荐的版本组合(Ubuntu 20.04/22.04 + Python 3.8 + SNPE 2.16),能避开90%的坑。剩下的10%,就需要靠仔细阅读错误信息、善用搜索和一点点耐心来解决。当你第一次看到自己的模型在手机上流畅跑起来的时候,会觉得这些折腾都是值得的。

更多推荐