3. 模型文件管理:.tflite、.h5、ONNX 等格式的存储与命名规范
说到模型文件管理,我见过太多团队在这上面栽跟头了。
有一次,一个同事跑过来问我:「上周那个精度 92% 的模型是哪个文件?」结果我们翻遍了共享文件夹,发现有三个名字差不多的 .h5 文件,谁也不敢删。最后只能一个个重新跑测试。
你想想看,这种混乱多耽误事。所以今天我就把这几年的文件管理心得,好好跟你聊聊。
3.1 不同格式的「性格」差异
先说个基本概念。.h5、.tflite、ONNX 这三种格式,说白了就是不同阶段的「快照」。
| 格式 | 特点 | 我常用的场景 |
|---|---|---|
| .h5 | Keras 原生格式,包含完整网络结构 + 权重 | 训练阶段、微调、断点续训 |
| .tflite | Google 的移动端/嵌入式格式,量化后体积小 | 部署到 STM32、手机端 |
| .onnx | 开放神经网络交换格式,跨框架通用 | 框架转换、中间桥梁、模型分析 |
我个人习惯是:训练阶段只保留 .h5,部署阶段只保留 .tflite,ONNX 只作为转换中间件。这样思路清晰,不会乱。
核心原则:一个模型只保留一份「权威版本」,其他格式都是从这个版本转换来的。
3.2 命名规范:别再叫「final_model.h5」了
「final_model.h5」—— 我敢打赌,你电脑里至少有三个同名文件。
为什么?因为没人会只训练一次。你改个学习率、加个层、换个激活函数,都是新版本。所以命名必须带上关键信息。
我推荐这套命名规则:
项目名_模型架构_数据集_输入尺寸_量化方式_精度_日期_版本号.格式
举个例子:
gesture_cnn_v2_emg128_96x96_fp32_92.3_20240315_v1.0.tflite
gesture_cnn_v2_emg128_96x96_int8_89.7_20240315_v1.0.tflite
你看,光看文件名就知道:
- 项目是手势识别
- 用的是 CNN v2 架构
- 数据集是 emg128
- 输入是 96x96
- FP32 精度 92.3%,INT8 精度 89.7%
- 2024年3月15日生成的 v1.0 版本
嗯,这里要注意:精度一定要写验证集上的准确率,不是训练集。我见过有人写训练集 99.9%,结果验证集只有 60%,那这个数字就没意义了。
我的小技巧:用 Python 脚本自动生成文件名,避免手写错误。每次训练完,脚本自动提取精度、日期、量化方式,拼成标准文件名。
3.3 存储目录结构:别把所有文件扔一个文件夹
我曾经接手过一个项目,一个文件夹里躺着 200 多个 .tflite 文件。你猜怎么着?没人知道哪个是最终版本。
所以我建议这样组织目录:
models/
├── 01_原始模型/ # 从训练框架直接导出的 .h5
│ ├── v1.0/
│ └── v2.0/
├── 02_转换中间件/ # ONNX 文件,用于跨框架验证
│ ├── v1.0/
│ └── v2.0/
├── 03_部署模型/ # 最终部署用的 .tflite
│ ├── fp32/
│ ├── int8/
│ └── float16/
├── 04_测试报告/ # 每个模型的精度、延迟、内存占用
│ ├── v1.0_report.md
│ └── v2.0_report.md
└── 05_废弃版本/ # 不要删,但也不要混淆
└── v0.9/
为什么要有「废弃版本」文件夹?
因为有时候你发现新版本不如旧版本,想回退。但如果你把旧版本删了,那就真回不去了。我吃过这个亏,所以现在所有版本都保留,只是把不用的挪到废弃目录。
警告:千万不要在模型文件名里写「最终版」、「绝对最终版」、「打死不改版」。相信我,你一定会改的。
3.4 版本号管理:语义化版本
我推荐用语义化版本号:主版本.次版本.修订号
- 主版本:模型架构大改(比如从 CNN 换成 Transformer)
- 次版本:训练策略变化(学习率、优化器、数据增强)
- 修订号:小修小补(改了量化参数、修复了 bug)
举个例子:
v1.0.0 → 第一个可用版本
v1.1.0 → 改了学习率策略,精度从 90% 提升到 92%
v1.1.1 → 修复了量化校准集的一个 bug,精度不变
v2.0.0 → 换了 MobileNetV3 架构,精度 94%
为什么会这样设计?因为当你需要回退时,版本号能告诉你「这次改动有多大」。如果只是修订号变了,那直接换文件就行。如果主版本变了,那你得重新做一遍部署测试。
3.5 元数据文件:给模型写个「身份证」
光靠文件名还不够。我习惯在每个模型旁边放一个 metadata.json 文件:
{
"model_name": "gesture_cnn_v2",
"version": "1.0.0",
"framework": "TensorFlow 2.15",
"dataset": "emg128_v3",
"input_shape": [1, 96, 96, 1],
"output_shape": [1, 10],
"accuracy": {
"train": 0.956,
"validation": 0.923,
"test": 0.918
},
"quantization": "int8",
"latency_ms": 12.3,
"ram_kb": 48,
"flash_kb": 32,
"training_date": "2024-03-15",
"training_duration": "2h 15m",
"notes": "增加了数据增强,解决了过拟合问题"
}
这个 JSON 文件的好处是:
- 机器可读,可以写脚本自动分析
- 人类可读,一眼就知道模型的所有信息
- 可以自动生成测试报告
我的习惯:训练脚本最后一步自动生成 metadata.json,然后和模型文件一起打包。这样永远不会忘记记录关键信息。
3.6 避坑指南:我踩过的那些坑
坑一:我曾经把 .h5 和 .tflite 混在一起,结果部署时拿错了文件。后来我强制规定:训练目录只放 .h5,部署目录只放 .tflite,中间用 ONNX 做转换验证。
坑二:有一次我删除了一个「看起来没用」的 .h5 文件,结果发现那是唯一一个能跑出 92% 精度的版本。从那以后,我建立了「废弃版本」目录,所有文件至少保留 3 个月。
坑三:命名里写「v1_final」和「v1_final2」这种,等于没写。一定要用语义化版本号,并且用脚本自动生成,避免人为错误。
3.7 总结:我的文件管理清单
好了,说了这么多,给你一个可以直接用的清单:
- 命名格式:项目_架构_数据集_输入_量化_精度_日期_版本.格式
- 目录结构:原始模型 / 转换中间件 / 部署模型 / 测试报告 / 废弃版本
- 版本号:主版本.次版本.修订号,语义化
- 元数据:每个模型配一个 metadata.json
- 自动化:用脚本生成文件名和元数据,不要手写
- 保留历史:不要删旧版本,挪到废弃目录
你想想看,如果每个团队成员都遵守这套规范,还会出现「哪个模型是最终版」这种问题吗?
嗯,肯定不会。这就是我这些年总结出来的经验,希望能帮你少走弯路。