2、ARM设备环境准备:交叉编译工具链安装、ARM Linux系统配置、依赖库安装(OpenBLAS、NEON)
好,咱们正式开始动手了。
这一章,说白了就是给ARM设备“搭窝”。你想想看,ONNX Runtime要在ARM上跑得快,底层环境必须稳。我见过太多人,模型选得挺好,代码写得也漂亮,结果栽在环境配置上——编译不过、链接报错、跑起来直接崩。嗯,咱们别走那条路。
2.1 交叉编译工具链安装
先聊工具链。为什么需要交叉编译?因为你的开发机是x86架构,目标设备是ARM架构。直接在ARM上编译?太慢了,尤其是一些大型依赖库,编译一次够你喝杯咖啡再睡一觉。所以,咱们在PC上编译好,再丢到ARM板上跑。
我个人习惯用gcc-arm-linux-gnueabihf这套工具链。它支持硬件浮点,性能更好。安装很简单:
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
装完之后,验证一下:
arm-linux-gnueabihf-gcc --version
看到版本号,就说明成了。
gcc-aarch64-linux-gnu。别搞混了,我刚开始就踩过这个坑。
还有一个细节:工具链的命名规则。比如 arm-linux-gnueabihf 里的 hf 代表 hard float,也就是硬件浮点。如果你的ARM芯片不支持硬件浮点(比如一些老款Cortex-A5),那就得用 gnueabi 版本。不过现在主流ARM设备基本都支持,放心用 hf 就行。
2.2 ARM Linux系统配置
工具链装好了,接下来配置ARM Linux系统。这里我假设你用的是树莓派或类似的开发板,系统是Raspbian或Ubuntu ARM版。
首先,确保系统内核支持你需要的功能。我个人建议开启以下选项:
- NEON支持:ARM的SIMD指令集,ONNX Runtime的加速利器
- VFPv3或VFPv4:浮点运算加速
- 大页内存(HugeTLB):减少TLB miss,提升推理性能
检查NEON是否开启:
cat /proc/cpuinfo | grep neon
如果有输出,说明NEON已经可用。没有的话,你可能需要重新编译内核。嗯,这个操作有点麻烦,我建议直接换一个支持NEON的系统镜像,省心。
接下来,配置网络和SSH。毕竟你不想每次都插屏幕和键盘吧?
sudo apt-get install openssh-server
sudo systemctl enable ssh
sudo systemctl start ssh
然后记下ARM设备的IP地址,用SSH连上去:
ssh pi@192.168.1.100
搞定。以后开发就方便了。
2.3 依赖库安装:OpenBLAS
OpenBLAS是ONNX Runtime的底层矩阵运算库。没有它,推理速度会慢得让你怀疑人生。
安装OpenBLAS有两种方式:
方式一:apt直接安装(推荐新手)
sudo apt-get install libopenblas-dev
简单粗暴,但版本可能比较老。如果你对性能要求不高,这样够用了。
方式二:源码编译(推荐追求极致性能)
我个人更喜欢这种方式,因为可以针对具体ARM芯片做优化。比如,指定目标架构为Cortex-A72:
git clone https://github.com/xianyi/OpenBLAS.git
cd OpenBLAS
make TARGET=CORTEXA72 HOSTCC=gcc CC=arm-linux-gnueabihf-gcc
sudo make install PREFIX=/usr/local/openblas
这里 TARGET 参数很关键。你想想看,如果你用Cortex-A76的优化参数去编译,结果跑在Cortex-A53上,性能反而会下降。所以,一定要查清楚你的ARM芯片型号。
2.4 依赖库安装:NEON优化库
NEON是ARM的SIMD指令集,说白了就是一条指令同时处理多个数据。ONNX Runtime里很多算子都依赖NEON加速。
NEON不需要额外安装库,它是CPU指令集的一部分。但你需要确保编译ONNX Runtime时开启了NEON支持。这个我们下一章会详细讲。
不过,有些第三方库可以帮你更好地利用NEON。比如 ARM Compute Library,它封装了NEON指令,提供了卷积、池化等常用操作的优化实现。
安装ARM Compute Library:
git clone https://github.com/ARM-software/ComputeLibrary.git
cd ComputeLibrary
scons Werror=1 -j8 neon=1 opencl=0 os=linux arch=armv8a
注意 arch=armv8a 这个参数。如果你的设备是32位的ARMv7,就改成 arch=armv7a。别搞错了,否则编译出来的库根本跑不起来。
benchmark=1 参数,可以生成性能测试工具。我经常用它来对比不同优化策略的效果。
2.5 验证环境是否就绪
所有东西装完后,写个简单的测试程序,验证交叉编译和依赖库是否正常。
创建一个 test.c:
#include <stdio.h>
#include <cblas.h>
int main() {
float a[4] = {1.0, 2.0, 3.0, 4.0};
float b[4] = {5.0, 6.0, 7.0, 8.0};
float result;
// 调用OpenBLAS的点积函数
result = cblas_sdot(4, a, 1, b, 1);
printf("Dot product: %f\n", result);
return 0;
}
用交叉编译器编译:
arm-linux-gnueabihf-gcc test.c -o test -lopenblas
然后把 test 文件传到ARM设备上,运行:
./test
如果输出 Dot product: 70.000000,说明环境一切正常。
cannot find -lopenblas,说明链接路径没配好。检查一下 /usr/local/openblas/lib 是否在 LD_LIBRARY_PATH 里。我当初就因为这个报错折腾了半小时。
2.6 本章小结
好,到这步,你的ARM设备环境就基本搭好了。我们做了三件事:
- 安装了交叉编译工具链,让PC能编译ARM程序
- 配置了ARM Linux系统,开启了NEON和SSH
- 安装了OpenBLAS和ARM Compute Library,为ONNX Runtime铺路
下一章,咱们就要正式编译ONNX Runtime了。到时候你会发现,今天这些准备工作,每一分每一秒都值。
嗯,先到这。有问题随时翻回来看看。