第1章:开发环境搭建——交叉编译工具链安装、SSH远程开发、Python虚拟环境配置、ONNX Runtime与TFLite Runtime的交叉编译

大家好,我是你们的嵌入式AI部署讲师。今天咱们正式开始第一课——把开发环境搭起来。

说实话,我见过太多同学卡在环境搭建这一步。明明模型训练得好好的,一到嵌入式设备上就各种报错。嗯,这很正常。嵌入式开发跟服务器开发完全是两码事。你想想看,一个ARM Cortex-A系列的小芯片,要跑一个几十MB的深度学习模型,中间要跨过多少坑?

所以这一章,我带你一步步把交叉编译工具链、SSH远程开发、Python虚拟环境,还有ONNX Runtime和TFLite Runtime的交叉编译全部搞定。别急,咱们慢慢来。

本章核心目标:在x86主机上搭建一套完整的嵌入式AI推理开发环境,能够编译出在ARM Linux设备上运行的推理引擎。

嵌入式AI推理部署环境搭建流程 x86主机开发环境 Ubuntu 20.04/22.04 交叉编译工具链 aarch64-linux-gnu-gcc 推理引擎交叉编译 ONNX Runtime / TFLite ARM SSH远程开发 VS Code Remote-SSH Python虚拟环境 conda / venv 文件传输 scp / rsync / sftp 最终产物:可在ARM Linux上运行的推理引擎 + Python绑定 部署流程:模型转换 → 量化 → 交叉编译 → 传输 → 运行验证 ONNX/TFLite模型 → INT8量化 → ARM可执行文件 → scp到设备 → 测试

1.1 交叉编译工具链安装

先说说交叉编译。说白了,就是在你的x86电脑上编译出能在ARM芯片上跑的程序。为什么不能直接在ARM设备上编译?因为嵌入式设备资源有限,编译一个ONNX Runtime可能要半小时,而在x86上只要几分钟。

我个人习惯用Linaro提供的工具链,稳定且社区活跃。以aarch64(ARMv8 64位)为例:

# 下载aarch64交叉编译工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz

# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz -C /opt/

# 配置环境变量
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
export CC=aarch64-linux-gnu-gcc
export CXX=aarch64-linux-gnu-g++

小提示:我建议把环境变量写到 ~/.bashrc~/.zshrc 里,这样每次打开终端就不用重新设置了。记得 source 一下。

验证是否安装成功:

aarch64-linux-gnu-gcc --version
# 输出类似:aarch64-linux-gnu-gcc (Linaro GCC 7.5-2019.12) 7.5.0

嗯,看到版本号就说明工具链装好了。这里要注意,工具链版本要和目标设备的glibc版本匹配。我曾经遇到过用高版本工具链编译的程序,在低版本glibc的设备上跑不起来,报错说找不到符号。后来老老实实降级了工具链版本。

1.2 SSH远程开发

嵌入式设备通常没有显示器,我们通过SSH连接上去操作。我个人强烈推荐VS Code的Remote-SSH插件,体验非常好。

基本配置步骤:

  1. 在嵌入式设备上开启SSH服务:sudo systemctl start sshd
  2. 在主机上生成SSH密钥:ssh-keygen -t rsa -b 4096
  3. 将公钥复制到设备:ssh-copy-id user@device_ip
  4. 配置VS Code Remote-SSH,连接设备

避坑指南:我曾经在配置SSH时忽略了设备的IP地址变化问题。嵌入式设备如果使用DHCP,重启后IP会变,导致VS Code连不上。建议在路由器上绑定MAC地址和IP,或者给设备设置静态IP。

文件传输方面,我常用rsync,比scp快很多,特别是传输大文件时:

# 将本地目录同步到设备
rsync -avz --progress ./build/ user@192.168.1.100:/home/user/project/

# 从设备拉取文件
rsync -avz --progress user@192.168.1.100:/home/user/logs/ ./logs/

1.3 Python虚拟环境配置

做AI部署,Python环境是绕不开的。我建议在主机上使用conda管理虚拟环境,在设备上使用venv(因为conda在ARM上支持不太好)。

主机上的配置:

# 创建conda环境
conda create -n embedded_ai python=3.8
conda activate embedded_ai

# 安装常用依赖
pip install numpy opencv-python pillow onnx onnxruntime

设备上的配置(ARM Linux):

# 设备上安装Python3和venv
sudo apt-get install python3 python3-venv python3-pip

# 创建虚拟环境
python3 -m venv /home/user/venv/embedded_ai
source /home/user/venv/embedded_ai/bin/activate

# 安装纯Python依赖(不需要交叉编译的)
pip install numpy

注意:设备上的numpy等包需要从源码编译,或者使用预编译的ARM wheel包。我建议在设备上直接 pip install numpy,它会自动下载ARM版本的wheel。如果下载慢,可以配置国内镜像源。

1.4 ONNX Runtime交叉编译

这是本章的重头戏。ONNX Runtime的交叉编译,说白了就是让它在ARM Linux上能跑起来。我踩过不少坑,这里给你一个经过验证的流程。

首先,下载ONNX Runtime源码:

git clone --recursive https://github.com/microsoft/onnxruntime.git
cd onnxruntime
git checkout v1.15.1  # 选择一个稳定版本

然后,配置交叉编译参数。这里有个关键点——要指定CMAKE_TOOLCHAIN_FILE:

# 创建交叉编译工具链文件
cat > /opt/aarch64-toolchain.cmake << EOF
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
EOF

开始编译:

./build.sh --config Release \
  --build_shared_lib \
  --parallel \
  --cmake_extra_defines CMAKE_TOOLCHAIN_FILE=/opt/aarch64-toolchain.cmake \
  --arm64 \
  --enable_onnx_tests=OFF

小提示:编译时间取决于你的CPU核心数。我一般用 --parallel 参数,让编译并行进行。第一次编译大概需要20-30分钟,耐心等待。

编译完成后,产物在 build/Linux/Release/ 目录下。主要文件:

  • libonnxruntime.so — 动态链接库
  • onnxruntime — 可执行文件
  • include/ — 头文件

把这些文件传输到设备上,就可以在ARM Linux上运行ONNX模型了。

1.5 TFLite Runtime交叉编译

TFLite的交叉编译相对简单一些。Google官方提供了预编译的ARM库,但我建议自己编译,这样可以定制优化选项。

# 下载TensorFlow源码
git clone https://github.com/tensorflow/tensorflow.git
cd tensorflow
git checkout v2.13.0

# 配置交叉编译
./configure  # 按提示选择ARM交叉编译选项

# 编译TFLite静态库
bazel build --config=elinux_aarch64 \
  //tensorflow/lite:libtensorflowlite.so

如果你不想用bazel(说实话,bazel确实有点重),可以用CMake方式:

cd tensorflow/lite
mkdir build && cd build

cmake .. \
  -DCMAKE_TOOLCHAIN_FILE=/opt/aarch64-toolchain.cmake \
  -DTFLITE_ENABLE_XNNPACK=ON \
  -DTFLITE_ENABLE_GPU=OFF

make -j$(nproc)

经验之谈:我建议开启XNNPACK优化,它在ARM CPU上有显著的加速效果。GPU支持在嵌入式设备上通常不成熟,我一般关掉。另外,如果设备支持NEON指令集,可以加上 -DTFLITE_ENABLE_NEON=ON

编译产物:

  • libtensorflowlite.so — TFLite动态库
  • benchmark_model — 性能测试工具
  • label_image — 图像分类示例

1.6 环境验证

所有东西都编译好了,怎么验证?我一般写一个简单的测试程序:

// test_ort.c
#include <onnxruntime/core/session/onnxruntime_c_api.h>
#include <stdio.h>

int main() {
    const OrtApi* api = OrtGetApiBase()->GetApi(ORT_API_VERSION);
    OrtSessionOptions* session_options;
    api->CreateSessionOptions(&session_options);
    
    printf("ONNX Runtime version: %s\n", api->GetVersionString());
    printf("Environment setup successfully!\n");
    
    api->ReleaseSessionOptions(session_options);
    return 0;
}

交叉编译并传输到设备上运行:

# 主机上交叉编译
aarch64-linux-gnu-gcc test_ort.c -o test_ort \
  -I/path/to/onnxruntime/include \
  -L/path/to/onnxruntime/lib \
  -lonnxruntime

# 传输到设备
scp test_ort libonnxruntime.so user@device_ip:/home/user/

# 设备上运行
export LD_LIBRARY_PATH=/home/user:$LD_LIBRARY_PATH
./test_ort

如果看到版本号输出,恭喜你,环境搭建成功了!

常见问题:如果设备上运行时报错 cannot open shared object file,说明动态库路径没设置对。用 ldd test_ort 查看依赖,确保所有.so文件都能找到。我一般把库文件放在 /usr/local/lib 下,然后运行 ldconfig 更新缓存。

好了,这一章的内容就到这里。环境搭好了,后面的事情就顺了。下一章我们开始讲模型转换和量化,那才是真正有意思的部分。


专注资料整理