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

看到版本号,就说明成了。

小提示:如果你用的是aarch64(比如树莓派4B的64位系统),那就装 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的系统镜像,省心。

注意:有些廉价开发板为了省成本,用的芯片虽然标称支持NEON,但实际被厂家阉割了。我曾经买过一块板子,跑ONNX Runtime时死活不加速,查了两天才发现是硬件问题。所以,买板子前一定确认清楚。

接下来,配置网络和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芯片型号。

经验之谈:我在项目中遇到过,同一块板子,用apt安装的OpenBLAS推理一次要120ms,换成源码编译优化后,直接降到45ms。差距就是这么大。

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。别搞错了,否则编译出来的库根本跑不起来。

小技巧:编译ARM Compute Library时,加上 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了。到时候你会发现,今天这些准备工作,每一分每一秒都值。

嗯,先到这。有问题随时翻回来看看。