最近在整理 Memoria 项目的端侧多模态部署资产。前面已经把 MobileCLIP / MobileCLIP2 的 ONNX、TFLite 版本整理并发布到了 Hugging Face,这次继续往移动端部署方向推进,把 NCNN 版本也补进了同一个模型资产仓库。

这篇文章主要记录这次 NCNN 版本的整理过程,包括:为什么要补 NCNN、如何把已有 NCNN runtime 文件纳入 release、如何避免误传 SDK 和中间产物、如何补上 ONNX-vs-NCNN 数值一致性验证,以及为什么暂时没有发布 MobileViCLIP-small 的 NCNN 半成品。

Hugging Face 仓库地址:

https://huggingface.co/youthfedpycharm/memoria-mobile-vision-assets

一、为什么要给模型资产补 NCNN 版本?

Memoria 是一个面向移动端的 AI-native 智能相册项目,核心目标是让相册具备端侧语义理解、自然语言检索、照片聚类、截图过滤等能力。

在移动端部署视觉语言模型时,只有 PyTorch checkpoint 是远远不够的。为了实际部署,需要把模型转成更适合端侧推理的格式,比如 ONNX、TFLite、NCNN、CoreML、MNN 等。

前面已经完成了 MobileCLIP / MobileCLIP2 的 ONNX 和 TFLite 发布,这次补充 NCNN 的原因主要有三个。

第一,NCNN 是移动端部署里非常常见的高性能推理框架,尤其适合 Android、边缘端、嵌入式设备。

第二,NCNN 的 .param/.bin 文件形式非常适合直接放进 App assets 里调用,比 PyTorch checkpoint 更接近真实产品部署。

第三,对于 Memoria 这种项目来说,发布 NCNN 资产可以让项目从“能跑实验”进一步变成“具备移动端落地能力”。

所以这次的目标不是简单地继续上传一个模型文件,而是把 Memoria Mobile Vision Assets 从 ONNX/TFLite 扩展到 ONNX + TFLite + NCNN 的移动端部署矩阵。

二、这次发布的 NCNN 资产是什么?

这次发布的是 MobileCLIP-S2 的 NCNN runtime assets,不是 MobileViCLIP-small。

这一点要特别说明,因为之前我也在考虑 MobileViCLIP-small 的 NCNN 版本,但最终发现它当前还有一些转换和验证问题,因此没有把半成品发出去。

本次真正发布到 Hugging Face 的是:

mobileclip-s2/ncnn/image_encoder.ncnn.param

mobileclip-s2/ncnn/image_encoder.ncnn.bin

mobileclip-s2/ncnn/text_encoder.ncnn.param

mobileclip-s2/ncnn/text_encoder.ncnn.bin

mobileclip-s2/ncnn/projection_layer.ncnn.param

mobileclip-s2/ncnn/projection_layer.ncnn.bin

这六个文件分别对应 MobileCLIP-S2 的 image encoder、text encoder 和 projection layer。

总大小约 378.2 MiB。

这些文件来自本地 assets/ncnn/mobileclip_s2/ 目录,我在整理时只上传了 canonical NCNN 模型本体,没有上传 third_party/ncnn SDK,也没有上传 build/intermediates 里的重复文件、中间产物、日志、token、API key 或本地私有路径。

三、为什么不能只上传模型,还要做验证?

很多时候,模型格式转换最容易出现的问题不是“转不出来”,而是“看起来转出来了,但输出不对”。

尤其是视觉模型,输入预处理稍微不一致,最后 embedding 就可能出现明显偏差。

比如 RGB / BGR 顺序不一致、是否除以 255、mean/std 是否一致、resize 方式是否一致、NHWC/CHW 顺序是否一致,都会影响最终结果。

所以如果只是把 .param/.bin 发上去,而没有任何验证结论,别人无法判断这个 NCNN 模型是不是真的可用。

这次我补了一个正式的验证路径:用 ONNX 作为 reference,对比 NCNN image encoder 的输出。

验证指标包括:

min cosine similarity

max absolute error

mean absolute error

最终结果如下:

NCNN image encoder vs ONNX

min cosine similarity: 0.9999998807907104

max abs error: 0.00014653801918029785

mean abs error: 1.544954496542535e-05

status: passed

这个结果说明,在相同输入条件下,NCNN image encoder 和 ONNX reference 的输出高度一致,模型本体转换是可靠的。

四、一个非常关键的坑:不能直接把 CHW numpy 塞进 NCNN

这次验证过程中踩到的一个坑非常关键。

一开始如果直接把 CHW numpy tensor 塞进 Python ncnn,指标可能会假性崩掉。这个问题不是模型真的错了,而是输入路径和 NCNN Android native 侧真实使用方式不一致。

正确做法是走更接近 Android native 侧的路径:

ncnn.Mat.from_pixels_resize

substract_mean_normalize

也就是说,应该让 NCNN 按它自己的图像输入路径来构造 Mat,而不是简单地把已经整理好的 numpy tensor 强行塞进去。

这个细节非常重要,因为同一个模型,如果输入构造方式不一致,最后得到的 cosine 可能会让人误判模型转换失败。

修正之后,MobileCLIP-S2 的 ONNX-vs-NCNN 验证结果达到了 0.99999988 的最低余弦相似度,说明之前可能出现的异常并不是模型本体问题,而是输入路径问题。

五、验证结果应该怎么表述?

这里还需要注意一个表述边界。

这次验证的是:

direct-resize RGB unit-scale 输入张量下的 ONNX-vs-NCNN 模型一致性验证。

它不是完整 Android 图像预处理链路 parity。

换句话说,这个验证证明的是:在同一套受控输入条件下,NCNN image encoder 和 ONNX reference 输出高度一致。

但是它不能直接等价于:

Android 端 Bitmap 解码、resize、RGB/BGR、mean/std、native pipeline 的完整链路已经和 Python 完全一致。

所以在 model card 和博客里,我不会把它夸大成“完整 Android 预处理链路验证通过”,而是更准确地写成:

在 direct-resize RGB unit-scale 输入下,NCNN image encoder 与 ONNX reference 的最低余弦相似度达到 0.99999988,最大绝对误差约 1.47e-4。

这个说法更严谨,也更不容易被反驳。

六、Hugging Face 仓库现在的模型矩阵

经过这次更新,Memoria Mobile Vision Assets 的模型矩阵大致如下。

MobileCLIP-S2:

ONNX:已发布

TFLite fp16:已发布

NCNN:已发布 image encoder、text encoder、projection layer

验证:ONNX passed,TFLite passed,NCNN image encoder passed

MobileCLIP2-S0:

ONNX vision/text encoder:已发布

验证:ONNX passed

MobileCLIP2-S2:

ONNX vision/text encoder:已发布

验证:ONNX passed

MobileCLIP2-B:

ONNX vision/text encoder:已发布

验证:ONNX passed

这使得整个仓库不再只是一个 ONNX/TFLite 文件集合,而更像一个面向移动端部署的视觉语言模型资产库。

七、版本管理:v0.2-mobileclip-s2-ncnn

这次更新后,我给 Hugging Face 仓库打了一个新 tag:

v0.2-mobileclip-s2-ncnn

这个版本的核心含义是:

在 Memoria Mobile Vision Assets 中为 MobileCLIP-S2 补充 NCNN runtime assets,并提供 ONNX-vs-NCNN image encoder 数值一致性验证。

之前的 v0.1-mobileclip-s2-mobileclip2-s2 tag 没有移动,仍然保留为最初的稳定发布点。

这样做的好处是版本语义更清楚:

v0.1 表示最早的 ONNX/TFLite 稳定发布。

v0.2 表示新增 MobileCLIP-S2 NCNN 资产和验证。

main 分支可以继续迭代,但旧版本 tag 不会被覆盖。

八、为什么没有直接发布 MobileViCLIP-small NCNN?

这次也尝试看了一下队友发布的 MobileViCLIP-small ONNX 资产。

队友的仓库是:

https://huggingface.co/szw0407/mobileviclip_small_onnx

其中主要文件是:

mobileviclip_small_vision.onnx

这个 ONNX 的输入输出结构是:

input: video [1, 8, 3, 256, 256]

output: embedding [1, 512]

也就是说,它不是普通的 4D image input,而是 5D video input,包含时间维度。

我尝试用 pnnx 转换它,pnnx 能生成一组 .ncnn.param/.bin 文件,但当前还不能作为可发布资产。

主要问题有两个。

第一个问题是,原始转换后的 final Normalize 层在 NCNN load_model 阶段失败。

第二个问题是,即使去掉 final Normalize,推理阶段又会卡在 5D video 输入到 NCNN/Python binding 的维度支持上。

因此我没有把 MobileViCLIP-small NCNN 半成品上传到 Hugging Face。

这是一个比较重要的工程判断:不能为了凑模型矩阵,把不可验证、不可稳定运行的文件发出去。模型资产发布不是“能生成文件就行”,而是至少要能 load、能推理、能验证。

九、MobileViCLIP-small NCNN 后续应该怎么做?

MobileViCLIP-small 的 NCNN 版本不是不能做,而是需要换一条更适合 NCNN 的导出路线。

我认为比较稳的 v0.3 路线是:

第一,从 MobileViCLIP 的 PyTorch/export 代码侧重新导出一版 NCNN-friendly ONNX。

第二,把 video/time 维度显式处理成 NCNN 更容易支持的输入结构,避免直接让 NCNN 吃 5D 输入。

第三,把最后的 L2 normalize 从模型图里移出来,放到后处理阶段做。

第四,再用 pnnx 或 onnx2ncnn 转换成 NCNN。

第五,跑 ONNX-vs-NCNN 数值验证,至少得到 cosine similarity 和 max abs error。

第六,通过验证后再上传到 Hugging Face,并打 v0.3-mobileviclip-small-ncnn tag。

这条路线虽然比直接转换麻烦,但结果更可靠,也更适合公开发布。

十、这次对 release 工具链做了什么修改?

这次不只是手动上传文件,也同步更新了 release 工具链。

主要改动包括:

第一,在 manifest 和 release pipeline 中加入 NCNN awareness,让 mobileclip-s2 能识别和复制 ncnn 目录下的 .param/.bin 文件。

第二,更新 release_summary.json,让总 summary 能显示 NCNN 资产。

第三,更新 HF model card,让页面中能展示 mobileclip-s2 的 NCNN runtime assets 和验证结果。

第四,更新 validate_export.py,使其支持 ncnn/image_encoder 的 ONNX-vs-NCNN 验证。

第五,更新 README,说明 NCNN 验证的输入条件和适用范围,避免把模型 parity 说成完整 Android pipeline parity。

这一步对工程质量很重要,因为如果只是手动复制文件,下次重新生成 release 的时候很容易丢掉 NCNN 资产。把它纳入工具链之后,后续迭代会更稳定。

十一、这件事对 Memoria 项目的意义

这次 NCNN 版本发布对 Memoria 的意义不只是“多了几个模型文件”。

它说明这个项目已经开始具备比较完整的端侧模型部署能力。

从项目叙事上看,Memoria 不只是一个智能相册 App,也不是单纯调用大模型 API,而是在逐步沉淀自己的移动端多模态基础设施。

目前已经有:

MobileCLIP / MobileCLIP2 的 ONNX 资产

MobileCLIP-S2 的 fp16 TFLite 资产

MobileCLIP-S2 的 NCNN runtime 资产

PyTorch-vs-ONNX 验证

TFLite 验证

ONNX-vs-NCNN 验证

Hugging Face model card

release_summary.json

批量导出和上传脚本

这些东西加起来,就不再是“我随手转了几个模型”,而是一套可复用、可追溯、可公开展示的移动端视觉语言模型部署资产库。

十二、总结

这次工作完成了 Memoria Mobile Vision Assets 的 v0.2 更新。

核心成果包括:

为 MobileCLIP-S2 补充 NCNN runtime assets。

发布 image encoder、text encoder、projection layer 的 .param/.bin 文件。

把 NCNN 资产纳入 Hugging Face release 矩阵。

补充 ONNX-vs-NCNN image encoder 数值一致性验证。

验证结果达到 min cosine 0.99999988,max abs error 约 1.47e-4。

修正 NCNN 输入路径,避免直接塞 CHW numpy 导致假性指标崩坏。

保留 v0.1 tag,新建 v0.2-mobileclip-s2-ncnn tag。

没有上传不可验证的 MobileViCLIP-small NCNN 半成品。

下一步计划是从 PyTorch/export 侧重新导出 NCNN-friendly 的 MobileViCLIP-small,再尝试发布 v0.3-mobileviclip-small-ncnn。

对我来说,这次最重要的收获是:模型部署资产不能只看“文件有没有转出来”,更要看“能不能稳定加载、能不能推理、能不能和 reference 对齐、能不能被别人复现”。

尤其是移动端模型,输入预处理和 runtime 行为非常容易出现隐藏差异。只有把导出、验证、发布和文档都整理清楚,才算真正完成了一个可以公开使用的模型资产。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐