关键词:ONNX, TFLite, 量化 (Quantization), YOLOv8, Android
大家好,我是飞哥!👋
前几个月我们一直在云端“冲浪”,用 Python 调 API、玩 Docker。
但作为一名 Android 开发者,你肯定心痒痒:“能不能不联网,直接在手机上跑 AI?”
答案是:必须能!但有个前提:你不能把云端那个几百 GB 的“大胖子”模型直接塞进手机里,手机会爆炸的(夸张了,是会卡死)。💥
今天这节课,飞哥就教你一门“瘦身缩骨功”——模型量化与格式转换。
1. 为什么要量化?(Why)
锚定已知 ⚓️
大家平时发微信视频,是不是经常会被压缩?原本 100MB 的高清视频,发过去只有 5MB,画质稍微糊了一点点,但看起来差不多,而且传输极快。
生动类比 🍔
模型量化,就是给 AI 模型做“脱水处理” (Freeze-drying)。
- 云端模型 (FP32):就像一颗饱满多汁的新鲜苹果。精度极高(小数点后 32 位),但又重又大,必须放冷库(GPU 服务器)。
- 量化模型 (INT8):就像一片苹果干。虽然水分(精度)少了一点点,口感(效果)略有差异,但营养(核心能力)还在,最重要的是——轻便!随便一个小口袋(手机 NPU/CPU)就能装下。
提炼骨架 🦴
所以,端侧 AI 的核心流程就是:
训练 (PyTorch) ➡️ 转换 (ONNX) ➡️ 压缩 (TFLite/INT8) ➡️ 部署 (Android)
2. 核心概念详解 (What)
(1) ONNX:AI 界的“普通话” 🌏
不同的 AI 框架(PyTorch, TensorFlow, PaddlePaddle)就像各地的方言,互相听不懂。
ONNX (Open Neural Network Exchange)就是它们共同商定的“普通话”。
不管你是哪里训练出来的模型,先转成 ONNX,然后再翻译成手机能听懂的 TFLite 或 NCNN。
(2) TFLite:Android 的“亲儿子” 🤖
Google 专门为移动端定制的格式。它去掉了训练相关的累赘功能,只保留“推理”能力,专门为安卓手机优化。
(3) 量化 (Quantization) 📉
这是一个用精度换速度的游戏:
| 模式 | 精度 | 体积 | 速度 | 推荐指数 |
|---|---|---|---|---|
| FP32 | 32位浮点 | 100% (大) | 🐢 慢 | ❌ (云端用) |
| FP16 | 16位浮点 | 50% (中) | 🏃 快 | ✅ (Android 首选) |
| INT8 | 8位整数 | 25% (小) | 🚀 极快 | ⚡️ (NPU 加速必备) |
⚠️ 飞哥提示:INT8 虽然快,但需要“校准 (Calibration)”。这就像拍照时的“自动测光”。真实世界的光线(FP32)范围极大,而照片(INT8)能容纳的亮度有限。转换时,你需要先让模型看一些典型图片(校准数据),让它算出最佳的“曝光参数”(数据分布),这样才能保证压缩后的模型既不过曝也不死黑,保留住核心细节。
3. 实战项目:模型量化实验室 (How) 🛠️
我们要完成一个任务:下载 YOLOv8 模型,把它转换成 Android 能用的 TFLite 格式,并验证它没坏。
本项目代码已开源在:Week13_Model_Quantization文件夹。
第一步:安装依赖 📦
pipinstallultralytics onnx onnxruntime tensorflow opencv-python第二步:一键导出 (export.py) 📤
YOLOv8 官方极其贴心,一行代码就能搞定。
fromultralyticsimportYOLOimportshutilimportosdefexport_models():print("🚀 开始加载 YOLOv8n 模型...")# 1. 下载/加载模型model=YOLO('yolov8n.pt')# 2. 导出为 ONNX (通用格式)print("\n📦 正在导出为 ONNX 格式...")model.export(format='onnx',opset=12)# 3. 导出为 TFLite (FP16 - 推荐)# half=True 表示使用 FP16 半精度,体积减半,精度几乎不损print("\n📦 正在导出为 TFLite (FP16) 格式...")model.export(format='tflite',half=True)print("\n✅ 导出完成!")# 移动文件到 models 目录os.makedirs("models",exist_ok=True)forfinos.listdir('.'):iff.endswith('.onnx')orf.endswith('.tflite')orf.endswith('.pt'):try:shutil.move(f,f"models/{f}")except:passprint("\n📂 模型已移动到 models/ 文件夹")if__name__=="__main__":export_models()运行后,你会发现models文件夹里多了yolov8n_float16.tflite,大小只有yolov8n.pt的一半!
第三步:Python 端验证 (inference.py) 🔍
很多同学转完模型直接扔进 Android 项目,结果报错一脸懵。
飞哥教你一招:先在 Python 里用tensorflow.lite跑一遍,确保模型本身没问题。
importtensorflowastfimportnumpyasnpimportcv2importtimeimportosdefrun_inference(tflite_path,image_path):print(f"\n🔍 开始测试模型:{tflite_path}")# 1. 加载 TFLite 模型interpreter=tf.lite.Interpreter(model_path=tflite_path)interpreter.allocate_tensors()# 2. 获取输入输出详情input_details=interpreter.get_input_details()output_details=interpreter.get_output_details()input_shape=input_details[0]["shape"]# [1, 640, 640, 3]print(f"📥 模型输入形状:{input_shape}")# 3. 预处理图片img=cv2.imread(image_path)ifimgisNone:print("❌ 找不到图片,请检查路径")return# Resize 到模型要求的尺寸 (通常是 640x640)img_resized=cv2.resize(img,(640,640))# 归一化 (0-255 -> 0-1)input_data=img_resized.astype(np.float32)/255.0input_data=np.expand_dims(input_data,axis=0)# 增加 batch 维度# 4. 推理start_time=time.time()interpreter.set_tensor(input_details[0]["index"],input_data)interpreter.invoke()output_data=interpreter.get_tensor(output_details[0]["index"])end_time=time.time()print(f"⚡️ 推理耗时:{(end_time-start_time)*1000:.2f}ms")print(f"📤 输出形状:{output_data.shape}")# ---------------------------------------------------------# 💡 飞哥小课堂:这个 (1, 84, 8400) 是什么意思?# ---------------------------------------------------------# 1. Batch Size (1): 我们一次只喂了一张图片。# 2. Channels (84): 代表每个预测框包含的信息量。# - 前 4 个数:是框的位置 (中心点x, 中心点y, 宽w, 高h)。# - 后 80 个数:是 COCO 数据集 80 个类别的概率 (比如它是猫的概率、是车的概率...)。# - 4 + 80 = 84# 3. Anchors (8400): YOLO 在这张图上总共生成了 8400 个候选框。# - 它是怎么算出来的?(640x640 图片)# - 80x80 (大特征图,看小物体) = 6400# - 40x40 (中特征图,看中物体) = 1600# - 20x20 (小特征图,看大物体) = 400# - 总和:6400 + 1600 + 400 = 8400# ---------------------------------------------------------print("✅ 测试通过!模型可以正常工作。")if__name__=="__main__":# 自动查找模型并运行# 确保你已经有了 models/yolov8n_saved_model/yolov8n_float16.tflite 和 assets/bus.jpgpass# (完整代码请参考 Week13_Model_Quantization/inference.py)第四步:使用 Netron 查看“内脏” 🔬
拿到模型后,必须看一眼它的结构。
下载神器Netron(也有网页版)。
打开yolov8n.onnx,关注两个点:
- Input:
images(1, 3, 640, 640) -> 记住这个尺寸,Android 端处理图片时必须一模一样。 - Output:
output0(1, 84, 8400) -> 这是 YOLO 的原始输出(84 = 4个坐标 + 80个类别概率)。
⚠️ 进阶技巧:
在 Android 上解析1x84x8400这种原始数据非常痛苦(需要自己写 NMS 算法)。
如果你想偷懒,可以在导出时加上nms=True(仅部分版本支持),或者使用专门为 TFLite 优化的 YOLO 版本。
4. 总结与作业 📝
一句话记住它:
模型量化就是给 AI 做“脱水压缩”,牺牲一丢丢精度,换取手机上的极致速度。
核心三要点:
- ONNX是中转站,TFLite是终点站。
- FP16性价比最高(体积减半,精度不降)。
- INT8虽快,但需要校准数据,且可能有精度损失。
本周作业:
- 运行
export.py导出你自己的 TFLite 模型。 - 用 Netron 截图模型的输入输出节点。
- (选做) 尝试开启
int8=True,看看体积还能小多少?
下篇,我们将正式进入Android (Jetpack Compose),把这个 TFLite 模型装进手机,做一个能看懂世界的 App!🚀
🎁 课程示例
我用夸克网盘给你分享了「Week13_Model_Quantization.zip」,点击链接或复制整段内容,打开「夸克APP」即可获取。
/483d3ADEGx😕 链接:https://pan.quark.cn/s/69cf8e9d25e4
源码包内含:
- ✅
export.py:一键导出脚本 - ✅
inference.py:Python 验证脚本 - ✅
requirements.txt:环境依赖清单 - ✅ 超详细 README 文档,小白也能跑通!