ONNX Runtime 移动端部署指南:在 Android 与 iOS 上跑通推理的 5 个环节
【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime
把图像分类模型塞进 App,是移动端 AI 最常见的起步场景:一个几十 MB 的 .onnx 文件,要放进 assets 或 bundle,再在用户的设备上完成一次推理。ONNX Runtime 移动端部署要解决的,就是这条从 ONNX 文件到张量输出的链路。读完这篇,你会知道:推理在设备上到底分几步、NNAPI 和 Core ML 什么条件下走、模型量化怎么操作、两个平台各贴一段能跑的关键代码,以及三个最值得调的数字。
一张图看懂推理链路:ONNX 文件 → Session → EP → 张量
整个链路四步:ONNX 模型只是文件,加载后由Session持有并做算子图优化;执行提供器(EP)决定每个算子跑在哪——CPU 还是 NNAPI / Core ML 这类硬件路径;张量则是输入输出的实际容器,形状必须与模型声明一致。Java 侧入口类是 OrtEnvironment / OrtSession,Objective-C 侧对应 ORTEnv / ORTSession,接口一一对应。
选执行路径:NNAPI 与 Core ML 的适用条件和降级
| 执行路径 | 适用设备 / 系统 | 生效条件 | 不满足时 |
|---|---|---|---|
| NNAPI | Android 8.0+,芯片带 NPU/DSP | 模型算子可映射到 NNAPI 子图 | 不支持的算子按子图回退 CPU,会话不报错,只变慢 |
| Core ML | iOS 15+(Core ML 5 及以上) | 算子可被 Core ML 编译器接管 | 实现里有use_cpu_only选项,可强制全 CPU;iOS 15 以下 EP 不可用 |
| CPU | 所有设备 | 默认兜底 | — |
版本映射的依据在 host_utils.h 头部注释:iOS 15 对应 Core ML 5、iOS 16 对应 6,以此类推。NNAPI 的实现位于 onnxruntime/core/providers/nnapi/。建议的写法是:默认加 EP,同时保留 CPU 路径,出问题时通过日志确认实际走了哪条路,而不是猜测。
模型瘦身三步:导出、量化、校验
1. 导出:固定 batch 与分辨率,do_constant_folding=True;动态 shape 会显著增加后续量化与 EP 转换的难度,移动端优先定长。
2. 量化(INT8 / FP16):仓库内的工具链在 onnxruntime/python/tools/quantization/(含 README),静态量化的标准用法:
python -m onnxruntime.tools.quantization.quantize_static \ --input model_fp32.onnx --output model_int8.onnx \ --per_channel --calibration_data calibration_setFP16 走--quant_format QDQ加--float16参数,收益主要是内存减半,精度损失比 INT8 小。
3. 校验:创建 Session 时抛异常即模型不合规;批量回归可用仓库里的测试工具:
adb push build/Android/Release/onnx_test_runner /data/local/tmp/ adb shell 'cd /data/local/tmp && ./onnx_test_runner <模型目录>'流程与输出格式见 docs/Android_testing.md。
Android 与 iOS 各跑一次推理
| 维度 | Android(Java/Kotlin) | iOS(Objective-C/Swift) |
|---|---|---|
| 依赖管理 | Maven AAR(onnxruntime-android) | CocoaPods(ONNXRuntime) |
| 模型放置 | src/main/assets,运行时经 InputStream 读出 | Xcode bundle,运行时取 URL |
| 创建会话 | OrtEnvironment+env.createSession(modelBytes, options) | ORTEnv+[[ORTSession alloc] initWithEnv:...] |
| 执行推理 | session.run(Map<String, OnnxTensor>) | [session runWithInputs:outputNames:error:] |
| 默认加 EP | NNAPI(硬件允许时) | Core ML(iOS 15+) |
Android 关键代码(模型从 assets 读入后创建会话):
OrtEnvironment env = OrtEnvironment.getEnvironment(); SessionOptions options = new SessionOptions(); options.setIntraOpNumThreads(2); // 线程数别开满,见下节 byte[] model = readFromAssets("model_int8.onnx"); OrtSession session = env.createSession(model, options); // 每次推理:按模型声明形状创建输入张量 long[] shape = {1, 3, 224, 224}; OrtSession.Result result = session.run( Map.of("input", OnnxTensor.createTensor(env, inputFloats, shape)));iOS 关键代码:
ORTEnv *env = [ORTEnv envWithLoggingLevel:ORTLoggingLevelWarning error:&err]; ORTSessionOptions *opts = [[ORTSessionOptions alloc] init]; // 默认追加 Core ML 执行提供器(iOS 15 起) [session appendExecutionProvider:ort_Provider_CoreML options:nil error:&err]; ORTSession *session = [[ORTSession alloc] initWithEnv:env options:opts error:&err]; // 推理: ORTValue *input = [ORTValue tensorWithValue:inputData shape:@[@1, @3, @224, @224] dataType:ORTTensorTypeFloat error:&err]; NSArray<ORTValue *> *outs = [session runWithInputs:@[input] outputNames:@[@"output"] error:&err];Objective-C 实现位于 objectivec/,Java 侧说明见 java/README.md。
调三个数字:延迟、内存、精度
延迟——线程数不是越多越好。跨核通信与缓存竞争会吃掉小模型上的收益:
options.setIntraOpNumThreads(2); // 通常取核心数的 1/2 起测内存——两个开关:SessionOptions 开启 memory optimization 与enable_memory_format(省中间张量拷贝);整体会话的分配策略见 docs/Memory_Optimizer.md,Arena 复用是移动端内存峰值的主要来源。
精度——量化后必须离线比对 FP32 输出再上车:
from onnxruntime.capi import _pybind_state as r print(r.get_build_info()) # 先用 CPU EP 跑 FP32/INT8 两版,记录输出差异差异超出业务可接受范围就回退 FP16 或只对部分层量化(量化工具支持按算子排除)。
容易踩的坑:现象 → 原因 → 处理
1. NNAPI 下速度没提升。部分算子不支持 NNAPI,整段子图静默回退 CPU,日志级别不够时看不出来。 调高日志等级(SessionOptions 的 log level),确认哪些算子落在 CPU 上;必要时候选方案是换 CPU EP 全量执行,或裁剪模型中的长尾算子。
2. Core ML EP 在低版本系统上完全不可用。仓库中 host_utils.h 明确最低支持 Core ML 5(iOS 15)。 按运行时系统版本分支:低于 iOS 15 时不追加 Core ML EP,直接走 CPU,不要指望 EP 自动降级。
3. 量化后模型加载失败或输出异常。最常见是原模型含动态 shape,或校准数据与真实分布不匹配。 导出时定长化;校准集换成线上真实数据的抽样;用 INT8 与 FP32 的输出差异做验收门槛。
4. 真机崩、模拟器正常(或反之)。ABI 与构建架构不匹配:模拟器通常要--android_abi x86_64,真机要 arm64-v8a;另外 AAR 需覆盖目标设备位宽。 按 docs/Android_testing.md 的分段构建说明,为模拟器和真机分别产出对应 ABI 的库。
源码与上述全部文档位于仓库 onnxruntime。下一步建议直接看 onnxruntime/python/tools/quantization/README.md 里量化工具的完整参数,以及用onnx_test_runner把回归测试固化进 CI。
【免费下载链接】onnxruntimeONNX Runtime: cross-platform, high performance ML inferencing and training accelerator项目地址: https://gitcode.com/GitHub_Trending/on/onnxruntime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考