4、开发环境搭建:交叉编译工具链、ONNX Runtime、TensorFlow Lite、NCNN的安装与配置
好,咱们进入实战环节的第一步——搭环境。
说实话,我见过太多人卡在这一步。工具链版本不对、库冲突、编译报错……折腾一整天,代码一行没写。所以这一章,我会把每个坑都指出来。
你想想看,嵌入式开发不像PC,你不能直接在板子上装个pip就完事。你得在PC上写好代码,然后交叉编译,再丢到板子上跑。这个流程里,工具链就是桥梁。
4.1 交叉编译工具链:ARM GCC的安装
交叉编译工具链,说白了就是一套能在PC上生成ARM机器码的编译器。我个人习惯用gcc-arm-none-eabi,它支持ARM Cortex-M系列,轻量且稳定。
安装步骤(Ubuntu 20.04/22.04):
# 添加ARM官方源
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt update
# 安装
sudo apt install gcc-arm-none-eabi
# 验证
arm-none-eabi-gcc --version
嗯,这里要注意:如果你用的是树莓派或者RK3588这类Cortex-A系列芯片,那得用aarch64-linux-gnu-gcc。别搞混了,我刚开始就吃过这个亏。
避坑指南:我曾经在Ubuntu 18.04上直接apt安装,结果版本是4.9,太老了,编译出来的二进制在板子上跑不起来。后来我改用PPA源,装的是9.3版本,一切正常。建议你至少用9.x以上版本。
4.2 ONNX Runtime:从源码编译到部署
ONNX Runtime是微软开源的推理引擎,支持跨平台。但嵌入式设备上,你不能直接pip install,得自己编译。
为什么会这样?因为ONNX Runtime默认带了CPU、CUDA、TensorRT等一堆后端,你板子上根本用不到。所以我们要做的是——最小化编译。
4.2.1 编译ONNX Runtime for ARM Linux
# 克隆源码
git clone --recursive https://github.com/microsoft/onnxruntime.git
cd onnxruntime
# 配置交叉编译
./build.sh --config Release \
--build_shared_lib \
--arm64 \
--cmake_extra_defines CMAKE_TOOLCHAIN_FILE=cmake/toolchains/aarch64-linux-gnu.toolchain.cmake \
--skip_tests
# 编译(-j4根据你的CPU核心数调整)
make -j4
编译完成后,在build/Linux/Release/下会生成libonnxruntime.so和头文件。把这些拷到你的板子上就行。
我的经验:如果你板子内存小(比如只有512MB),编译时加上--minimal_build参数,能省掉不少算子支持,库体积能缩小到原来的1/3。
4.3 TensorFlow Lite:轻量级部署方案
TFLite是Google专门为移动端和嵌入式设计的。它的核心思路是:先把模型转成.tflite格式,然后用TFLite Runtime加载推理。
我个人建议,别用TensorFlow全家桶,太重了。你只需要TFLite Runtime和转换工具。
4.3.1 安装TFLite Runtime
# 在PC上安装Python版(用于模型转换)
pip install tflite-runtime
# 在ARM板子上,下载预编译的whl包
# 访问:https://github.com/nicktaj/tflite-runtime-armv7l/releases
# 选择对应Python版本和架构
pip install tflite_runtime-2.14.0-cp39-cp39-linux_aarch64.whl
注意:TFLite Runtime和TensorFlow的版本要对应。比如你用TF 2.14训练的模型,最好也用2.14的Runtime。版本不匹配,模型加载时会报错。
4.3.2 模型转换示例
import tensorflow as tf
# 加载你的模型
model = tf.keras.models.load_model('my_model.h5')
# 转换
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT] # 量化优化
tflite_model = converter.convert()
# 保存
with open('model.tflite', 'wb') as f:
f.write(tflite_model)
量化这一步很关键。我做过测试,FP32转INT8后,模型体积缩小4倍,推理速度提升2-3倍,精度只掉了不到1%。
4.4 NCNN:腾讯开源的移动端推理框架
NCNN是我在国产芯片上用得最多的框架。它没有第三方依赖,纯C++实现,对ARM架构优化得特别好。
你想想看,NCNN连OpenCV都不需要,就一个头文件和几个so文件,往板子上一丢就能跑。这种轻量感,用过的都懂。
4.4.1 编译NCNN
git clone https://github.com/Tencent/ncnn.git
cd ncnn
mkdir build && cd build
# 交叉编译配置
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/aarch64-linux-gnu.toolchain.cmake \
-DNCNN_BUILD_TOOLS=ON \
-DNCNN_BUILD_EXAMPLES=OFF \
-DNCNN_VULKAN=OFF \
..
make -j4
make install
避坑指南:我曾经在编译时忘了关NCNN_VULKAN,结果链接Vulkan库失败,折腾了两小时。如果你的板子没有GPU,或者GPU不支持Vulkan,一定要把这个选项关掉。
4.4.2 模型转换(ncnn2table + ncnn2int8)
NCNN支持从ONNX、Caffe、TensorFlow等格式转换。我一般用ONNX作为中间格式:
# 先把模型转成ONNX
# 然后用ncnn的转换工具
./onnx2ncnn your_model.onnx your_model.param your_model.bin
# 如果需要INT8量化
./ncnn2table your_model.param your_model.bin \
calibration_images/ \
your_model.table \
mean=[104,117,123] \
norm=[0.017,0.017,0.017]
./ncnn2int8 your_model.param your_model.bin \
your_model_int8.param your_model_int8.bin \
your_model.table
我的经验:校准图片最好用100-200张,覆盖各种场景。太少的话,量化后的模型在某些输入上精度会崩。我踩过这个坑,后来老老实实准备了200张图片,效果就稳了。
4.5 各框架对比与选型建议
| 框架 | 体积 | 推理速度 | 算子支持 | 量化支持 | 推荐场景 |
|---|---|---|---|---|---|
| ONNX Runtime | 中等(~5MB) | 快 | 丰富 | INT8/FP16 | 需要跨框架兼容 |
| TensorFlow Lite | 小(~1MB) | 较快 | 中等 | INT8 | Google生态、快速原型 |
| NCNN | 极小(~500KB) | 极快 | 中等 | INT8 | 国产芯片、极致优化 |
我个人建议:如果你刚开始接触嵌入式AI,先从TFLite入手,文档多、社区活跃。等熟悉了流程,再尝试NCNN做极致优化。ONNX Runtime适合需要同时支持多种模型格式的场景。
总结一下:
- 交叉编译工具链是基础,版本别太老
- ONNX Runtime要最小化编译,别贪多
- TFLite用Runtime就够了,不用装全家桶
- NCNN轻量高效,但需要手动处理模型转换
环境搭好了,下一章我们就开始实战——把MobileNet跑在板子上。到时候你会发现,前面这些折腾都是值得的。