3. 模型文件管理:.h5、.tflite、STM32Cube AI生成的C代码如何纳入Git

模型文件管理,说白了就是解决一个问题:哪些文件该进Git,哪些不该进,进了之后怎么管。

我见过不少团队,直接把整个训练目录往Git里一推,结果仓库体积飙到几个G,每次clone都像在下载电影。也见过另一种极端——只存代码,模型文件全扔本地,结果换台机器就得重新训练。

这两种做法,其实都不太对。

3.1 先搞清楚:你的模型文件到底有多大

在决定怎么管之前,先看看你手里有哪些文件。我列个表,你对照一下自己的项目:

文件类型 典型大小 是否建议进Git 备注
.h5 (Keras权重) 10MB ~ 500MB ❌ 不建议 二进制大文件,diff无意义
.tflite (量化模型) 100KB ~ 10MB ✅ 建议 体积可控,便于追溯
STM32Cube AI生成的C代码 50KB ~ 2MB ✅ 必须 文本文件,可diff
训练日志/checkpoint 几百MB ~ 几GB ❌ 绝对不要 用DVC或云存储
数据集 几GB ~ 几十GB ❌ 绝对不要 单独管理

核心原则:Git只存可追溯、可diff、体积可控的文件。大二进制文件用Git LFS或DVC管理。

3.2 我的推荐方案:分层管理

我个人习惯把模型文件分成三层,每层用不同的策略:

第一层:训练产物(.h5、checkpoint)

这些文件体积大、变化频繁、diff无意义。我建议:

  • 不进Git,用 .gitignore 排除
  • 用 DVC (Data Version Control) 管理版本
  • 或者上传到内部NAS / 云存储,用脚本记录版本号

我曾经在一个项目里,团队5个人同时训练,.h5文件互相覆盖,最后谁都不知道哪个版本是最终版。后来改用DVC,每个模型都带一个 .dvc 文件进Git,问题就解决了。

第二层:部署产物(.tflite、.onnx)

这些文件体积适中,是最终烧录到芯片上的东西。我建议:

  • 进Git,但用 Git LFS 管理
  • 文件名带上版本号或commit hash
  • 每次更新都写CHANGELOG

小技巧:.tflite文件虽然二进制,但你可以用 git diff --binary 看文件大小变化。如果量化后体积突然变大,说明量化没生效。

第三层:嵌入式代码(STM32Cube AI生成的C代码)

这是最容易被忽视的部分。很多人觉得C代码是自动生成的,没必要管。但我想说:必须管,而且要管好。

为什么?因为:

  • C代码是文本文件,Git可以diff,你能看到每次改了什么
  • STM32Cube AI生成的代码里包含模型结构、权重数组、输入输出配置
  • 如果模型版本和C代码版本对不上,烧录进去就是跑飞

3.3 实操:.gitignore怎么写

嗯,这里要注意。很多人的.gitignore写得不够细,要么漏了关键文件,要么把不该忽略的也忽略了。

我给出一个参考模板,你可以直接复制到项目里:

# 训练产物
*.h5
*.hdf5
*.ckpt
checkpoints/
logs/

# 数据集
data/raw/
data/processed/

# 临时文件
__pycache__/
*.pyc
.ipynb_checkpoints/

# 大模型文件(用LFS管理的除外)
*.onnx
*.pb

# 注意:.tflite 和 C代码 不忽略
# 它们应该进Git

警告:不要一股脑把 *.tflite 也写进.gitignore。你想想看,如果部署文件都不在Git里,你怎么保证烧录的版本和训练的一致?

3.4 版本命名规范:别让文件名变成灾难

我见过最离谱的命名:model_final_final_v2_really_final.h5。你肯定也见过。

我建议用这套命名规则:

文件类型 命名格式 示例
.h5 (训练) {项目}_{模型名}_v{版本}.h5 gesture_mobilenet_v2.3.h5
.tflite (部署) {项目}_{模型名}_v{版本}_{量化类型}.tflite gesture_mobilenet_v2.3_int8.tflite
C代码目录 {项目}_{模型名}_v{版本}/ gesture_mobilenet_v2.3/

3.5 核心流程:从训练到Git的完整链路

下面这张图,是我在实际项目中总结出来的流程。你看一遍就明白了:

模型文件管理流程:从训练到Git 阶段1:训练 输出:.h5 / checkpoint 阶段2:转换/量化 输出:.tflite 阶段3:Cube AI 输出:C代码 决策:哪些文件进Git? .h5 / checkpoint ❌ 不进Git 用DVC / 云存储 .tflite ✅ 进Git (LFS) 带版本号命名 C代码 ✅ 必须进Git 文本文件,可diff Git仓库:.tflite + C代码 + .dvc文件 .h5和数据集单独管理 💡 关键:版本号对齐 .tflite ↔ C代码 ↔ 烧录

3.6 避坑指南:我踩过的几个坑

做嵌入式AI这几年,我在模型文件管理上栽过不少跟头。分享几个典型的:

  • 坑1:C代码和.tflite版本不一致
    我曾经有一次,用v2.1的.tflite转换,但Cube AI生成C代码时误用了v2.0的配置文件。结果烧录后模型输出全是乱码。排查了两天才发现是版本对不上。
    解决方案:在C代码的注释里写上对应的.tflite版本号和commit hash。
  • 坑2:Git LFS配额用完
    免费GitHub LFS只有1GB存储和1GB带宽。如果你频繁更新大模型,很快会超限。
    解决方案:自建Git LFS服务器,或者用DVC + 对象存储。
  • 坑3:.gitignore漏了checkpoint目录
    有一次队友把整个checkpoints目录(3.2GB)推到了Git里,导致仓库无法clone。最后只能重写历史。
    解决方案:在项目初始化时就写好.gitignore,并让CI检查是否有大文件误入。

3.7 总结:记住这三条

  1. .h5不进Git,用DVC或云存储管理版本
  2. .tflite进Git(用LFS),文件名带版本号
  3. C代码必须进Git,它是最终烧录的依据,也是diff的凭证