news 2026/9/15 17:57:55

Moonshine 项目 Android ONNX Runtime 最小化构建指南:从源码编译、操作符裁剪与安装体积实测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Moonshine 项目 Android ONNX Runtime 最小化构建指南:从源码编译、操作符裁剪与安装体积实测

Moonshine 项目 Android ONNX Runtime 最小化构建指南:从源码编译、操作符裁剪与安装体积实测

【免费下载链接】moonshineVery low latency speech to text, intent recognition, and text to speech, for building voice agents and interfaces项目地址: https://gitcode.com/GitHub_Trending/moonshine3/moonshine

本指南面向 Moonshine 的开发者与维护者,讲解 Android 平台上 ONNX Runtime(ORT)运行库的供应链管理方案:为什么仓库内core/third-party/onnxruntime/lib/android/下的三个.so必须由源码构建而非直接下载官方 AAR,最小化构建对模型格式与执行提供程序(Execution Provider)产生了哪些硬性约束,以及如何在提交前验证裁剪与 strip 结果。读完本文,你将掌握scripts/build-ort-android.sh的完整用法、各 ABI 的体积收益数据,以及用scripts/measure-mobile-size.sh实测真实安装成本的流程。

目录

  1. 这些.so从哪来:源码构建而非下载
  2. 最小化构建的两条硬性约束
  3. 每个 ABI 的实测体积收益
  4. 构建脚本用法与参数详解
  5. 构建流程中的关键工程细节
  6. 跨平台版本锁:ort-build-common.sh
  7. 提交前的验证与真实安装体积测量

一、这些.so从哪来:源码构建而非下载

关联文档 core/third-party/onnxruntime/lib/android/README.md 开宗明义:仓库内android/目录下按 ABI 分目录存放的libonnxruntime.so(当前包含arm64/armeabi-v7a/x86_64/三个变体)不是从官方发布渠道下载的预编译产物,而是由scripts/build-ort-android.sh从源码构建后 vendor 进仓库的

这一点至关重要,原因有三:

  • 版本被固定:构建脚本将 ONNX Runtime 钉在特定版本(当前为1.23.2),避免官方 AAR 升级引入行为漂移;
  • 构建被裁剪:整个构建被限制到 core/third-party/onnxruntime/moonshine-required-operators.config 所列的操作符集合,只编译 Moonshine 模型真正用到的算子;
  • 产物被 strip:vendor 前会剥离符号与调试信息,否则仓库体积会失控。

因此文档明确警告:不要向这个目录投放标准的 ONNX Runtime AAR。上层所有代码都假设底层是一个最小化构建(minimal build),放入完整版库虽然能跑,但会破坏体积预算,并在行为上与其它平台不一致。

二、最小化构建的两条硬性约束

最小化构建(--minimal_build)会丢弃 ONNX 解析器与部分图优化器,由此产生两条在会话创建(session creation)时报错、而非编译时报错的约束,任何使用该库的调用方都必须遵守:

1. 只加载 ORT 格式模型(.ort

最小化构建中根本没有编译进 ONNX 解析器,因此.onnx文件在 Android(以及 WebAssembly、iOS)上永远无法被读取,无论调用代码怎么写。为消除"桌面端能用、移动端报晦涩解析错误"的双格式分裂,Moonshine 在所有平台统一只接受 ORT flatbuffer 编码的.ort模型。详细背景见 docs/ort-only-models.md。

对使用方的影响是:自行提供的自定义模型文件必须先用转换工具迁移:

python scripts/convert-models-to-ort.py path/to/model.onnx

转换后.onnx会在启动时报出指明文件名与本命令的错误信息,而不再是难以定位的解析异常。ONNX external data(model.onnx.data/model.onnx_data)支持也随之移除,因为.ort是自包含单文件。

2. 没有 NNAPI 执行提供程序

Android 库在默认构建中不包含 NNAPI execution provider。这不是疏漏,而是一个被量化过的工程决策——详见 docs/execution-providers.md:

  • NNAPI 是"编译型" provider,它把图中自己能识别的节点成组摘出、编译成自己的图,其余留给 CPU;每个编译组与 CPU 之间的边界都要付出同步(甚至跨内存拷贝)代价。因此决定它是否有用的关键指标不是"支持多少节点",而是"图被切成了几块"。
  • Moonshine 的模型以全优化方式转换为.ort,优化会把整段区域融合为com.microsoft域算子(FusedConvMultiHeadAttentionMatMulNBitsSkipLayerNormalization等),这些是 CPU 内核,任何编译型 provider 都不认识,反而把其余节点切成碎片。
  • 实测数据(由scripts/check-ep-partitioning.py复现):Piperen_US-amy-low被切成220 个分区,Piperen_US-saikat被切成141 个分区,Kokoro 148 个分区,没有一个模型能达到每分区 7 个节点的门槛。
  • NNAPI 本身的成本是 0.55 MB(约占 6.5 MB 库的 9%),换来的却是上述碎片化执行——边界开销大于加速收益,所以默认剔除。

ort_providers选项仍接受CoreMLNNAPI,但任何已发布库中都不包含它们,请求会返回指向 docs/execution-providers.md 的错误,而不是静默降速。

三、每个 ABI 的实测体积收益

文档给出了最小化构建替换 stock 1.23.2 mobile 库后的按 ABI 体积对比(单位 MB):

ABIStock mobileMinimalSaved
arm64-v8a18.56.012.5
armeabi-v7a13.33.79.6
x86_6422.16.415.7

一个设备只安装一个 ABI,因此一台 arm64 手机实际节省的是12.5 MB。操作符裁剪约砍掉了 ORT 约三分之二的代码——这是从源码 scripts/build-ort-android.sh 头部注释中明确记载的数字。

裁剪的核心机制是--include_ops_by_config:构建被限制到 moonshine-required-operators.config 列出的算子。该文件由 scripts/generate-ort-op-config.py 自动生成(文件头注明"Generated by ... do not edit by hand"),覆盖了仓库内全部 TTS 音色、转写模型、VAD、拼写模型等ai.onnx各版本段与com.microsoft扩展域算子(如FusedConvMultiHeadAttentionMatMulNBitsRotaryEmbedding等)。由于配置按模型清单生成,每当模型变更时都需重新生成;CI 中的check-ort-op-config测试负责强制这一点,防止构建出的库缺失新模型所需算子而在运行时失败。

四、构建脚本用法与参数详解

构建入口为 scripts/build-ort-android.sh,其用法签名如下:

scripts/build-ort-android.sh [force] [with-nnapi] [abi ...]
参数作用
force即使对应 ABI 的.so已存在也强制重建并重新 vendor
with-nnapi把 NNAPI 执行提供程序编回库中(默认剔除,见上文第二部分)
abiarm64-v8aarmeabi-v7ax86_64中的若干项,缺省时构建全部三个

支持的受控环境变量:

环境变量默认值说明
ANDROID_SDK_ROOT/ANDROID_HOME~/Library/Android/sdkAndroid SDK 路径
ANDROID_NDK_VERSION28.2.13676358构建所用 NDK 版本,需与 language-bindings/android/build.gradle.kts 中minSdk = 26匹配的应用保持一致
ANDROID_API26目标 API 级别;高于应用 minSdk 的 API 会导致库引用旧设备上不存在的符号
ORT_ANDROID_CONFIGRelease构建配置,可选MinSizeRel
MOONSHINE_ORT_ROOT~/moonshine-ort(或 wasm 构建遗留的~/moonshine-ort-wasmORT 源码检出与各平台构建树所在位置

关于构建配置,脚本注释特别提醒:MinSizeRel能把 arm64 从 Release 的 6.0 MB 压到 5.3 MB,省下约 0.7 MB(占 arm64 安装量的 3%),但它是靠-Os编译换来的速度折损,而 TTS 是实时性预算最紧的场景,模拟器计时又说明不了真机问题,因此该配置保持 opt-in:上真机测过再发布。

脚本还内置了智能跳过:如果请求的每个 ABI 都已在core/third-party/onnxruntime/lib/android/下存在,则直接退出并提示加force重建。

五、构建流程中的关键工程细节

深入 scripts/build-ort-android.sh 源码,可以看到几个不读源码就难以发现的工程细节:

ABI 目录名映射

ORT 构建体系内部把arm64-v8a称为arm64,因此 vendor 目录做了映射(见脚本dest_dir_for_abi()):arm64-v8alib/android/arm64/,其余两个与 ABI 名一致。这就是为什么仓库里是arm64/而非arm64-v8a/

用 NDK 自带的llvm-strip剥离

ORT 构建默认留下调试信息,未 strip 的 arm64 库约675 MB,其中约636 MB.debug*段(Gradle 打包时虽会丢弃,但仓库会通过 Git LFS 永久背着它,每个 clone 都受害)。脚本用 NDK 工具链自带的llvm-strip --strip-unneeded完成剥离——只有它才理解自己工具链的输出。同时脚本按宿主系统选择HOST_TAG(macOS 为darwin-x86_64,Linux 为linux-x86_64)。

KleidiAI 的交叉编译陷阱

ORT 1.23 只要宿主机是 arm64(如 Apple Silicon)就会为所有目标启用 KleidiAI,而不检查交叉编译目标,导致armeabi-v7ax86_64的源码被排除、代码路径却被启用,链接时因未定义ArmKleidiAI::Mlas*符号而失败。脚本对非 arm64 目标显式传--no_kleidiai规避。

强制重建时的陈旧缓存清理

ORT 的build.py只会向 CMakeCache 中添加-D,关闭某特性时不会移除旧的开关,因此force重建必须从空构建目录开始(脚本对已存在的构建目录执行清理),否则上次遗留的ON会让关闭标志静默失效——这是陈旧状态真正的来源。

六、跨平台版本锁:ort-build-common.sh

关联文档最后强调:保持每个 ABI 使用同一个 ORT 版本,并且与其它平台版本一致。这一约束由 scripts/ort-build-common.sh 落实,它被三个构建脚本(build-ort-android.shbuild-ort-wasm.shbuild-ort-ios.sh)共同 source,确保三者不会漂移:

  • 统一版本ORT_VERSION默认1.23.2,并须与 core/third-party/onnxruntime/find-ort-library-path.cmake 以及各平台未从源码构建的预编译库(core/third-party/onnxruntime/lib/*/README.md)保持一致。头文件在所有平台共享,库版本不一致可能在会话创建时才以诡异方式失败。
  • 共享检出:一个约 1 GB 的递归 ORT checkout 供所有平台复用(MOONSHINE_ORT_ROOT),因为算子裁剪写入构建目录而非源码树。
  • 共享最小化标志ort_minimal_flags()输出四组标志并附注释解释其必要性:
    • --minimal_build extended custom_ops:丢弃 ONNX 解析器与不可用的图优化器,extended保留运行时优化器(NNAPI/CoreML 这类加载期编译内核的 provider 必需),custom_ops保留自定义算子注册(ZipVoice 需要);
    • --include_ops_by_config <OP_CONFIG>:按算子配置文件裁剪;
    • --disable_ml_ops:去掉无模型使用的经典 ML(ai.onnx.ml)内核;
    • --compile_no_warning_as_error:绕开 ORT 1.23 最小化构建中-Werror,-Wunused-const-variable的编译失败,待上游修复后可移除。

脚本还提供ort_require_op_config()守护:算子配置文件缺失时直接报错并提示先运行scripts/generate-ort-op-config.py,防止无配置构建出完整体积的库。

七、提交前的验证与真实安装体积测量

验证库确实被 strip

替换任何.so之前,用文档给出的两条命令确认:

file <abi>/libonnxruntime.so # expect "stripped" strings -a <abi>/libonnxruntime.so | grep -o 'VERS_1\.[0-9.]*' | sort -u

第一条确认符号已被剥离(输出应含stripped),第二条确认版本符号符合预期(如VERS_1.23)。因为 Git LFS 会"乐意"永久携带调试信息,所以这一检查是提交前的硬性门槛。

测量真实安装成本

仓库磁盘上的.so大小并不能直接代表用户支付的成本:Android 的.so是整体随 AAR 发布的,但 AAR 里装着所有 ABI,而设备只下载一个。因此文档强调要用 scripts/measure-mobile-size.sh 读取构建出的 AAR(而非这些源码文件)来测量:

scripts/build-android.sh local && scripts/measure-mobile-size.sh android

从 scripts/measure-mobile-size.sh 源码看,measure_android()会自动在 Gradle 输出目录、发布目录与本地 Maven 缓存中选取最近修改的 AAR(支持MOONSHINE_AAR覆盖),用unzip -l逐 ABI 统计libonnxruntime.so与 AAR 内全部.so的总和,并明确输出"AAR total(没人下载这个)"与各 ABI 的真实下载量。脚本注释还点明了另一个反直觉事实:Gradle 会在打包时对原生库做 strip,中间产物(intermediates)约 98 MB,而实际发布约 18 MB,因此必须从 AAR 测量

该脚本同样支持 iOS 侧(measure_ios()通过真实链接最小二进制并报告__TEXT段大小),ios/all参数可对照使用——这也呼应了关联文档"与其它平台保持同版本、同思路"的跨平台一致性原则。


小结core/third-party/onnxruntime/lib/android/下的三个.so是 Moonshine 移动端体积与延迟预算的核心支柱。它由 scripts/build-ort-android.sh 从源码构建、按 moonshine-required-operators.config 裁剪算子、用 NDKllvm-strip剥离后 vendor 进仓库,换来 arm64 上每设备 12.5 MB 的安装节省;代价是只支持.ort模型且默认无 NNAPI。任何替换都必须遵守"同版本、同配置、验证 strip、从 AAR 实测"四条纪律。

【免费下载链接】moonshineVery low latency speech to text, intent recognition, and text to speech, for building voice agents and interfaces项目地址: https://gitcode.com/GitHub_Trending/moonshine3/moonshine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 17:55:12

网页的制作与建设全流程拆解:一份保姆级建站教程

网页的制作与建设全流程拆解:一份保姆级建站教程 域名买好了,服务器租下了,为什么网站还是打不开?这是我在过去十年接到的最频繁的问题。很多客户以为只要交了钱,网页就会像变魔术一样出现,结果卡在 DNS 解析、SSL 证书安装或者代码报错上,急得团团转。今天这篇关于 网页的制作与建设…

作者头像 李华
网站建设 2026/9/15 17:53:16

FlinkCDC同步性能卡死?读写解耦+Kafka并行度优化实战

先说结论&#xff1a;如果你的 FlinkCDC 数据同步任务遇到同步性能无法提升、怎么调 Sink 并行度吞吐都纹丝不动的情况&#xff0c;大概率问题不在 Sink 端&#xff0c;而是整条链路的写入并行度被上游 Source 的单通道给锁死了。这个坑我踩了一整天才彻底定位&#xff0c;当时…

作者头像 李华
网站建设 2026/9/15 17:52:51

在 Dokploy 上自托管 InsForge:Compose 应用部署与源码级配置指南

在 Dokploy 上自托管 InsForge&#xff1a;Compose 应用部署与源码级配置指南 【免费下载链接】InsForge The all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to…

作者头像 李华
网站建设 2026/9/15 17:52:50

如何安装 redis-py 并首次连接 Redis 完成一次 set/get 数据读写

如何安装 redis-py 并首次连接 Redis 完成一次 set/get 数据读写 【免费下载链接】redis-py Redis Python client 项目地址: https://gitcode.com/GitHub_Trending/re/redis-py 本文解决的问题是&#xff1a;你准备在一台机器上用 Python 操作 Redis&#xff0c;需要完成…

作者头像 李华
网站建设 2026/9/15 17:50:09

不会代码做网页?2026网页的制作与建设选型指南

不会代码做网页?2026网页的制作与建设选型指南 想做个网站展示产品,但一搜“网页的制作与建设”就头大? 满屏全是HTML、CSS、JavaScript,或者让你买服务器、备案、写代码。 自己不会代码想做网站,到底该怎么破局?…

作者头像 李华