前言
最近在做一个叫 Memoria(智能影记) 的项目,它的目标是做一个面向移动端的 AI-native 智能相册:在端侧完成照片理解、语义检索、相册聚类、截图过滤等任务,同时尽量保护用户隐私。
为了让多模态模型真正跑到移动端,光有 PyTorch checkpoint 是不够的。移动端更关心的是:
-
模型能不能导出成 ONNX?
-
能不能进一步转成 TFLite?
-
能不能做 float16 / int8 量化?
-
导出后的模型和原始 PyTorch 模型输出是否一致?
-
这些模型资产能不能公开发布、复现和复用?
因此,我这次围绕 Memoria 项目整理了一套独立的移动端视觉模型发布工具链,并把第一批模型资产发布到了 Hugging Face。
项目地址:
https://huggingface.co/youthfedpycharm/memoria-mobile-vision-assets
本次 v0.1 版本主要包含:
-
MobileCLIP-S2 ONNX
-
MobileCLIP-S2 float16 TFLite
-
MobileCLIP2-S2 vision encoder ONNX
-
MobileCLIP2-S2 text encoder ONNX
-
批量导出脚本
-
ONNX/TFLite 验证脚本
-
TFLite int8 量化脚本
-
Hugging Face 上传脚本
-
release summary / metrics / model card
一、为什么要做这件事?
在很多多模态项目里,模型实验阶段通常用的是 PyTorch:
model = load_model(...)
output = model(image)
但是一旦要部署到手机、边缘设备或者 Flutter App 里,就会遇到一堆现实问题:
-
PyTorch 模型太重,不适合直接端侧部署;
-
很多移动端推理框架更偏向 ONNX Runtime、TFLite、CoreML;
-
模型导出后可能会有数值误差;
-
导出的模型文件、预处理方式、验证指标如果不整理清楚,后续很难复现;
-
如果想把它作为项目亮点,需要有公开仓库和标准化说明。
所以这次我的目标不是"随手导出几个文件",而是整理成一套比较完整的 release pipeline:
PyTorch checkpoint
↓
ONNX export
↓
TFLite / float16 / int8 quantization
↓
PyTorch vs ONNX/TFLite validation
↓
生成 metrics.json / config.json / README.md
↓
上传 Hugging Face
二、工具链目录结构
我在项目里新增了一套独立的发布工具,目录如下:
ai_tools/mobile_vision_release/
├── export_mobile_vision_assets.py
├── validate_export.py
├── quantize_tflite_int8.py
├── upload_to_hf.py
├── release_manifest.example.json
└── README.md
每个文件的作用如下:
| 文件 | 作用 |
|---|---|
export_mobile_vision_assets.py |
按 manifest 批量生成 release 目录 |
validate_export.py |
对比 PyTorch 与 ONNX/TFLite 输出,并写入 metrics.json |
quantize_tflite_int8.py |
SavedModel 转 int8 TFLite |
upload_to_hf.py |
上传到 Hugging Face,默认 dry-run,显式 --execute 才真实上传 |
release_manifest.example.json |
MobileCLIP / MobileCLIP2 / MobileViCLIP 模型矩阵模板 |
README.md |
工具链完整使用说明 |
生成后的 release 目录位于:
build/mobile_vision_release/
当前 v0.1 的主要结构如下:
build/mobile_vision_release/
├── README.md
├── LICENSE
├── CITATION.cff
├── release_summary.json
├── mobileclip-s2/
│ ├── model.onnx
│ ├── model.float16.tflite
│ ├── config.json
│ ├── metrics.json
│ ├── README.md
│ └── scripts/
└── mobileclip2-s2/
├── model.onnx
├── text_model.onnx
├── config.json
├── metrics.json
├── README.md
└── scripts/
三、本次发布的模型资产
1. MobileCLIP-S2
MobileCLIP-S2 当前包含:
mobileclip-s2/
├── model.onnx
└── model.float16.tflite
文件大小:
| 文件 | 大小 |
|---|---|
model.onnx |
137.6 MB |
model.float16.tflite |
68.4 MB |
其中 model.onnx 已经从 external data ONNX 合并成了单文件,方便直接下载和使用。
ONNX 验证结果:
| 指标 | 数值 |
|---|---|
| min cosine similarity | 0.99999988 |
| max absolute error | 8.05e-7 |
这个结果说明 ONNX 导出后的输出和 PyTorch 参考模型基本一致。
TFLite 验证暂时跳过,原因是当前 Python 环境没有安装 TensorFlow。这个信息保留在了 metrics.json 和 model card 中,没有隐藏。
2. MobileCLIP2-S2
MobileCLIP2-S2 当前包含 vision encoder 和 text encoder:
mobileclip2-s2/
├── model.onnx
└── text_model.onnx
文件大小:
| 文件 | 大小 |
|---|---|
model.onnx |
136.4 MB |
text_model.onnx |
242.3 MB |
ONNX 验证结果:
| 指标 | 数值 |
|---|---|
| min cosine similarity | 0.99999994 |
| max absolute error | 5.36e-7 |
这个数值也比较理想,说明导出链路整体是稳定的。
四、批量导出命令
如果只想按 manifest 批量导出,可以使用:
python ai_tools/mobile_vision_release/export_mobile_vision_assets.py \
--run-export \
--run-validate
如果想指定模型,例如批量导出 MobileCLIP2 的多个变体:
python ai_tools/mobile_vision_release/export_mobile_vision_assets.py \
--models mobileclip2-s0,mobileclip2-s2,mobileclip2-b \
--run-export \
--run-validate
这种方式的好处是,后续新增模型变体时,不需要重新写一套导出逻辑,只需要修改 manifest 或指定模型名即可。
五、Hugging Face 上传脚本
原本设计的上传命令如下:
python ai_tools/mobile_vision_release/upload_to_hf.py \
--release-root build/mobile_vision_release \
--repo-id youthfedpycharm/memoria-mobile-vision-assets \
--execute \
--commit-message "Release Memoria mobile vision assets v0.1"
这里有一个安全设计:默认不真实上传,必须显式加上:
--execute
才会执行真正的 Hugging Face 上传。
这样可以避免误传大文件、误传私有文件或者把未检查的 release 目录直接发出去。
六、上传过程中的坑:hf upload-large-folder 卡在 Xet 预上传阶段
这次上传并不是一帆风顺。
最开始尝试使用:
hf upload-large-folder
这个命令理论上适合上传 500MB+ 的大目录,并且支持断点续传。
但是实际上传过程中,它卡在了 Xet pre-upload 阶段。日志显示大文件开始预上传,但长时间没有进入 commit 阶段。
后来又尝试普通的 hf upload,小文件上传也出现了超时问题。
最终解决方式是:
-
停掉残留的 hf / python 上传进程;
-
禁用 Xet 路径;
-
使用
huggingface_hub.HfApi逐文件上传; -
先上传 README、metadata、config、metrics、scripts 等小文件;
-
再逐个上传 ONNX / TFLite 大文件。
关键环境变量:
import os
os.environ["HF_HUB_DISABLE_XET"] = "1"
逐文件上传示例:
import os
from huggingface_hub import HfApi
os.environ["HF_HUB_DISABLE_XET"] = "1"
api = HfApi()
repo = "youthfedpycharm/memoria-mobile-vision-assets"
api.upload_file(
repo_id=repo,
repo_type="model",
path_or_fileobj=r"build/mobile_vision_release/mobileclip-s2/model.onnx",
path_in_repo="mobileclip-s2/model.onnx",
commit_message="Add MobileCLIP S2 ONNX asset",
)
这个方法虽然朴素,但非常稳。
最终几个大文件都成功上传:
mobileclip-s2/model.float16.tflite
mobileclip-s2/model.onnx
mobileclip2-s2/model.onnx
mobileclip2-s2/text_model.onnx
七、最终发布结果
最终 Hugging Face repo:
https://huggingface.co/youthfedpycharm/memoria-mobile-vision-assets
远端核对结果:
| 项目 | 结果 |
|---|---|
| 文件数 | 25 |
| 总大小 | 613,200,004 bytes |
| 版本 | v0.1 |
| 最新 commit | f26f0d4c7e6a0743926eec72c7cf9d1c36d90534 |
已包含主要文件:
README.md
LICENSE
CITATION.cff
release_summary.json
mobileclip-s2/model.onnx
mobileclip-s2/model.float16.tflite
mobileclip2-s2/model.onnx
mobileclip2-s2/text_model.onnx
mobileclip-s2/config.json
mobileclip-s2/metrics.json
mobileclip-s2/README.md
mobileclip-s2/scripts/
mobileclip2-s2/config.json
mobileclip2-s2/metrics.json
mobileclip2-s2/README.md
mobileclip2-s2/scripts/
八、Model Card 中需要注意的 License 问题
这里有一个比较重要的点:不要随便给模型资产标 MIT 或 Apache-2.0。
原因是:
-
工具脚本可以是 MIT;
-
但是导出的模型权重、ONNX、TFLite 属于上游模型资产的衍生物;
-
MobileCLIP / MobileCLIP2 的代码和模型许可并不完全等价;
-
如果多个模型混放在同一个 Hugging Face repo,最好使用
license: other,并在 README 里分别说明 attribution 和 upstream license。
因此我在 model card 里更倾向于使用类似:
---
license: other
license_name: mixed-upstream-licenses
tags:
- mobileclip
- mobileclip2
- onnx
- tflite
- quantization
- edge-ai
- mobile-ai
- vision-language-model
- memoria
library_name: onnx
pipeline_tag: zero-shot-image-classification
---
README 中再单独说明:
## License and Attribution
This repository contains deployment artifacts exported from upstream models.
- MobileCLIP / MobileCLIP2 artifacts are derived from their original upstream releases.
- Export scripts and release tooling in this repository are released under MIT unless otherwise stated.
- Users are responsible for complying with the original upstream licenses and terms when using the exported model artifacts.
这一步虽然麻烦,但是公开发布模型资产时非常重要。
九、这件事对 Memoria 项目的意义
这次发布不只是"传了几个模型文件",更重要的是让 Memoria 从一个应用原型,往前走了一步,变成了一个有工程沉淀的项目。
它至少体现了几个能力:
1. 移动端部署能力
不是只会调用大模型 API,而是开始考虑端侧模型格式、推理框架和部署资产。
2. 工具链工程能力
从导出、验证、量化到发布,都做成了脚本化流程,而不是手动操作。
3. 可复现能力
每个模型目录都有:
config.json
metrics.json
README.md
scripts/
后续别人可以知道这个模型怎么来的、怎么验证的、误差是多少。
4. 开源展示能力
发布到 Hugging Face 后,模型资产可以被公开访问、引用和下载,也可以作为项目展示的一部分。
5. 项目叙事能力
Memoria 不只是"智能相册 App",还可以描述为:
一个围绕端云协同、多模态理解、隐私友好相册智能与移动端模型部署构建的 AI-native 项目。
十、后续计划
当前 v0.1 主要完成了 MobileCLIP-S2 和 MobileCLIP2-S2。
后续计划包括:
-
补充 TensorFlow 环境,完成 TFLite 数值验证;
-
批量导出 MobileCLIP / MobileCLIP2 的 S0、S1、S2、B 等更多变体;
-
尝试 int8 TFLite 量化;
-
补齐 MobileViCLIP 的 source、license、checkpoint、paper attribution 后再发布;
-
建立 Hugging Face Collection,统一展示 Memoria 的移动端视觉模型资产;
-
将这些资产接入 Memoria App 的端侧语义检索流程。
总结
这次工作完成了 Memoria 移动端视觉模型资产的 v0.1 发布。
核心成果包括:
-
构建了一套独立的移动端视觉模型 release 工具链;
-
支持 ONNX / TFLite 导出;
-
支持 PyTorch vs ONNX/TFLite 数值验证;
-
自动生成 metrics、config、README 和 release summary;
-
成功发布到 Hugging Face;
-
MobileCLIP-S2 ONNX 与 PyTorch 输出 min cosine 达到 0.99999988;
-
MobileCLIP2-S2 ONNX 与 PyTorch 输出 min cosine 达到 0.99999994;
-
解决了 Hugging Face CLI / Xet 上传大文件卡住的问题,最终通过 HfApi 逐文件上传完成。
对我来说,这不是一次简单的模型文件上传,而是一次比较完整的移动端 AI 工程实践:从模型格式转换、数值验证、发布工具链,到公开 model card 和后续项目落地,都形成了一套可以继续扩展的基础设施。
后面如果继续补齐更多模型变体和 MobileViCLIP,这个仓库就可以成为 Memoria 项目的一个正式开源资产入口。