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的完整链路
下面这张图,是我在实际项目中总结出来的流程。你看一遍就明白了:
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 总结:记住这三条
- .h5不进Git,用DVC或云存储管理版本
- .tflite进Git(用LFS),文件名带版本号
- C代码必须进Git,它是最终烧录的依据,也是diff的凭证