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 总结:我的文件管理清单

好了,说了这么多,给你一个可以直接用的清单:

  1. 命名格式:项目_架构_数据集_输入_量化_精度_日期_版本.格式
  2. 目录结构:原始模型 / 转换中间件 / 部署模型 / 测试报告 / 废弃版本
  3. 版本号:主版本.次版本.修订号,语义化
  4. 元数据:每个模型配一个 metadata.json
  5. 自动化:用脚本生成文件名和元数据,不要手写
  6. 保留历史:不要删旧版本,挪到废弃目录

你想想看,如果每个团队成员都遵守这套规范,还会出现「哪个模型是最终版」这种问题吗?

嗯,肯定不会。这就是我这些年总结出来的经验,希望能帮你少走弯路。