4、模型包结构设计:学习模型包应包含的文件(模型文件、配置文件、校验信息、版本号等)及其组织规范
模型包是OTA升级链路中真正被传输、校验、落盘和加载的物理载体。在BM1684平台上,模型包结构设计的优劣直接决定了升级脚本的复杂度、回滚的成功率以及版本追踪的准确性。一个设计良好的模型包,应当让升级程序在不依赖外部数据库的情况下,仅通过解析包内文件即可完成版本判断、完整性校验和原子性切换。本节将围绕模型包的文件组成、目录规范、元数据设计以及签名校验机制展开,帮助学员建立一套可落地、可追溯的模型包组织标准。
4.1 模型包的核心文件组成
BM1684模型包并非简单地将编译产物打包上传,而是需要遵循一套严格的四要素规范:模型文件、配置文件、校验信息、版本元数据。缺少任何一项,都可能导致升级程序无法正确加载或回滚。
| 文件/目录 | 必选 | 说明 | 典型命名 |
|---|---|---|---|
| compiled.bmodel | 是 | BM1684编译后的二进制模型,含算子指令与权重 | yolov5s_int8.bmodel |
| config.json | 是 | 模型输入尺寸、归一化参数、阈值、后处理配置 | config.json |
| sha256sums.txt | 是 | 包内所有文件的SHA256哈希列表,用于完整性校验 | sha256sums.txt |
| VERSION | 是 | 纯文本,记录版本号、构建时间、git commit | VERSION |
| signature.sig | 强烈建议 | 对sha256sums.txt的RSA签名,防止篡改 | signature.sig |
| preprocess.py / postprocess.py | 可选 | 若预处理逻辑复杂,可附带参考脚本 | preprocess.py |
其中compiled.bmodel是唯一不可再生的文件,它由TPU-MLIR编译器根据训练好的模型和BM1684芯片特性生成。配置文件config.json则承担了“运行时解释器”的角色——同样的bmodel,配合不同的阈值或锚点配置,可能产生完全不同的业务效果。因此,配置文件的版本必须与模型文件强绑定,不能单独升级。
4.2 目录组织规范与命名约定
推荐采用“包名-版本号”作为根目录名,内部使用固定子目录结构。这样在设备端解压后,无需读取额外说明即可定位文件。
model_pkg_v2.1/
├── compiled.bmodel # 主模型文件
├── config.json # 运行时配置
├── sha256sums.txt # 哈希校验清单
├── VERSION # 版本元数据
├── signature.sig # RSA签名(可选但推荐)
├── assets/ # 辅助资源(标签文件、锚点表等)
│ ├── labels.txt
│ └── anchors.npy
└── logs/ # 构建日志(便于追溯)
└── build_20250610.log
命名规范建议:模型名_芯片型号_精度_版本号。例如yolov5s_bm1684_int8_v2.1.tar.gz。版本号采用语义化版本(SemVer)规则:主版本号.次版本号.修订号。主版本变化表示模型结构不兼容,次版本表示精度或功能增强,修订号表示bug修复或配置微调。
config.json中的input_shape字段必须与bmodel编译时的shape严格一致。如果使用动态shape,需要在配置中显式声明dynamic: true以及允许的shape范围,否则推理时会报错。
4.3 版本追踪与元数据设计
版本追踪的核心在于VERSION文件的设计。它不仅是给人看的,更是给OTA升级程序解析的。推荐使用键值对格式,便于脚本解析:
MODEL_NAME=yolov5s
CHIP=BM1684
PRECISION=int8
VERSION_MAJOR=2
VERSION_MINOR=1
VERSION_PATCH=0
BUILD_TIME=2025-06-10T14:30:00+08:00
GIT_COMMIT=3f8a2c9e1b7d4f6a8c0e2b5d7f9a1c3e5b7d9f0a
COMPILER_VERSION=tpu-mlir_v1.6.0
INPUT_SHAPE=1x3x640x640
OUTPUT_NODES=378,379,380
升级程序读取VERSION文件后,与设备当前运行版本进行比较,决定是否执行升级。同时,GIT_COMMIT字段让开发人员能够精确定位到训练或编译时的代码版本,这在排查“为什么新模型在特定场景下精度下降”时至关重要。
对于设备端已安装的模型,建议在/data/models/下维护一个manifest.json,记录当前激活版本和历史版本记录:
{
"active": "v2.1",
"history": [
{"version": "v2.0", "installed_at": "2025-05-20T10:00:00Z", "status": "rolled_back"},
{"version": "v2.1", "installed_at": "2025-06-11T09:30:00Z", "status": "active"}
]
}
4.4 校验信息与安全机制
OTA升级最怕两类问题:传输损坏和恶意篡改。前者通过SHA256哈希解决,后者需要RSA签名。
SHA256校验流程:
- 打包时,对包内每个文件计算SHA256,写入
sha256sums.txt。 - 设备端下载完成后,先解压到临时目录
/data/ota/tmp/。 - 逐文件计算SHA256,与
sha256sums.txt比对。 - 任何文件哈希不匹配,立即丢弃整个包,不触发升级。
RSA签名验证:为防止攻击者同时替换模型文件和哈希清单,需要对sha256sums.txt本身做签名。设备端预置公钥,升级时用公钥验证signature.sig是否由私钥签署。私钥仅保存在公司CI/CD服务器中。
/etc/ota_pubkey.pem),并设置只读权限。如果公钥被替换,攻击者可以伪造任意模型包。
4.5 实战案例:一次失败的模型包升级复盘
某安防场景客户反馈,升级到v2.1版本后,夜间检测率从85%骤降至40%。开发团队起初怀疑是模型过拟合,但回滚到v2.0后恢复正常。经过排查,问题出在配置文件与模型文件不匹配。
背景与约束:该客户使用BM1684盒子,通过OTA平台推送升级包。升级包由CI系统自动构建,但构建脚本中config.json是从另一个分支拉取的,该分支的输入分辨率是1280x720,而v2.1模型编译时使用的是640x640。
关键日志:
[2025-06-11 09:31:22] [INFO] OTA package downloaded, size=128MB
[2025-06-11 09:31:25] [INFO] SHA256 verification passed
[2025-06-11 09:31:26] [INFO] VERSION file parsed: v2.1
[2025-06-11 09:31:28] [WARN] config.json input_shape=1x3x1280x720, bmodel expects 1x3x640x640
[2025-06-11 09:31:28] [ERROR] Model load failed: input shape mismatch
分析过程:SHA256校验通过说明文件在传输中未损坏,但校验只保证“文件与打包时一致”,不保证“文件之间逻辑一致”。由于CI脚本错误地将另一个分支的config.json打入包内,导致模型加载失败。更隐蔽的是,如果加载器没有做shape校验,模型可能以错误的输入尺寸运行,产生不可预期的推理结果。
解决措施:
- 在CI脚本中增加一致性断言:解析config.json中的input_shape,与bmodel头信息比对,不一致则构建失败。
- 在设备端加载器中增加shape校验,不匹配时拒绝加载并回滚。
- 在VERSION文件中增加
CONFIG_SHA256字段,记录config.json自身的哈希,便于快速定位配置来源。
复盘经验:模型包设计不能只关注“文件是否齐全”,更要关注“文件间的一致性”。建议在打包阶段就生成一份manifest.json,记录每个文件的来源路径、编译参数、git分支,随包发布。这样即使出现问题,也能快速定位是哪个环节引入了错误。
4.6 常见误区与设计原则总结
在模型包结构设计中,以下误区最为常见:
| 误区 | 后果 | 正确做法 |
|---|---|---|
| 只打包bmodel,不带config | 设备端无法确定输入尺寸和阈值 | config.json必须与bmodel同包 |
| 版本号写在文件名中,不单独设VERSION文件 | 脚本解析困难,无法获取git commit | 使用标准VERSION文件,键值对格式 |
| SHA256只校验bmodel,不校验config | 配置文件被篡改可能导致错误推理 | 对包内所有文件计算哈希 |
| 升级时直接覆盖旧文件 | 升级中断导致设备变砖 | 先解压到临时目录,校验通过后rename |
| 忽略签名或使用对称加密 | 私钥泄露后攻击者可伪造包 | 使用RSA非对称签名,私钥仅存CI |
设计原则总结:
- 原子性:模型包要么整体生效,要么完全不生效,不允许出现半更新状态。
- 可追溯性:每个包必须能追溯到源码commit、编译参数、构建时间。
- 自描述性:包内文件应包含足够信息,使设备端无需外部数据库即可完成校验和加载。
- 最小权限:设备端只保留公钥,私钥不出公司网络。