改完代码,怎样知道 J6 图片程序没被改坏?一条回归检查命令
图片程序第一次跑出分类结果或检测框以后,往往还要继续改:调整图片处理、整理输出解码、换运行库,或者优化速度。改完程序仍然显示“运行成功”,原来正确的结果却可能已经变了。
之前的NV12实验就有这种情况:输入文件没变,只是复制到内存的方式写错,程序依然正常退出,十张图的检测框却从51个变成零个。
一、程序成功退出,为什么还要检查结果?
“程序成功退出”说明这次执行按程序约定结束了,但不会替我们判断输入颜色、内存组织或输出读法是否正确。
例如,改错NV12行拷贝时,输入文件本身仍然正确,只检查文件长度和内容看不出问题;继续检查模型的原始输出,才会发现模型读到的数据已经不同。
另一类错误发生在推理之后:本轮分类输出的各类别scale不同,直接按整数排序会读错名次;检测头用错scale也会改变结果。模型给出的原始数字没变,程序解释出来的类别或框却变了。
所以检查器分开比较六个位置:
检查位置 | 核对什么 |
|---|---|
模型文件 | 是否仍是基准对应的同一份HBM |
文件结构 | 输入、输出文件是否齐全,名称与有效长度是否对应 |
进程状态 | 图片程序实际返回的退出码是否为0 |
输入文件 | 本张固定图片生成的数据是否与基准一致 |
原始输出 | 模型返回的有效数字是否与基准一致 |
任务结果 | 分类前五名或最终检测框是否对应 |
模型、输入和原始输出使用SHA-256内容哈希核对,可以理解成比较文件的内容指纹;不需要人眼阅读二进制文件。
这些检查给出的是排错起点:输入变了,先查图片处理;输入没变而原始输出变了,再查模型和执行路径;前两者一致、最终结果不同,就查输出解码与后处理。如果本来就在更新模型,模型哈希变化是预期现象,需要审查新结果并重新建立基准。
例如,修改画框代码后,图片仍能打开,程序也正常退出。报告若显示“输入通过、原始输出通过、检测结果告警”,就可以先回到解码和坐标还原这一步检查,不必重新怀疑整条模型部署流程。
二、基准和当前结果怎样留得可信?
基准是以前已经核对过的模型、输入、输出和任务结果。本轮使用的正常结果来自真实J6E运行,执行器与官方工具的控制对照另有记录。模型和图片固定,比较才有明确含义。
因此工具分成两个脚本:
脚本 | 负责什么 |
|---|---|
capture_cli_record.py | 启动本系列图片入口,记录真实退出码和产物路径 |
regression_check.py | 读取记录,比较文件和任务结果,生成报告 |
在J6E MatrixB上,我新跑了一张分类图片和两张检测图片,三次都通过检查。随后故意传入不存在的图片:实际进程退出1,检查器也返回1,并报告失败状态与缺失文件。即使磁盘上还留着以前的正确结果,非零进程状态也不会被抵消。
全部检查通过时,检查命令返回0;任一检查告警则返回1,同时写出JSON报告。已有报告不会被覆盖,方便保留修改前后的记录。
三、检查器自己也出过错:框没变,只是顺序变了
工具第一次接到板端结果时,就出现了一次误报。
图片181591的九个检测框,在SDK与自有程序中可以对应上,但列表保存顺序不同。第一版按列表下标比较,发现“第4项不是原来的框”,就把结果判成变化。
检测框的排列通常不影响含义:先保存猫框还是先保存人框,仍然是同一批预测。分类前五名却不同,第一名和第二名交换,排名本身已经变化。
修正后的规则是:分类按名次比较类别;检测不要求列表顺序相同,只要求每个框都能找到同类别、位置与分数相符的对应框。
原误报记录保留,修正后先重查相同数据,再重新执行三张图片,均通过。分类名次、检测排列、重复框、文件损坏和失败后残留旧结果等情况,原实验另有16个检查用例,均已通过。
四、121例回放说明了哪些检查有用?
我把已有数据整理成121个文件回放案例,来源分开记录:
40个正常控制:30个分类、10个检测。
29个真实板端输入故障结果:分类预处理错误9个、检测U/V交换10个、错误行拷贝10个。
50个本地后处理变化:在真实原始输出上改变分类整数排序30个、检测scale解码10个、坐标还原10个。
2个本地导出损坏:分类、检测各截短一个原始输出文件。
这是保存文件的回放,不是新增121次上板推理。实验环境为OE 3.9.1、UCP 3.15.8、HBRT 4.11.11,对照固定ResNet18和YOLOv5s。

图1|每格是该层告警数/该组案例数。输入文件、原始输出和任务结果分开检查,能够看到不同错误出现在哪一层。
案例 | 数量 | 输入告警 | 原始输出告警 | 任务结果告警 |
|---|---|---|---|---|
正常控制 | 40 | 0 | 0 | 0 |
分类颜色或归一化错误 | 9 | 9 | 9 | 9 |
检测U/V交换 | 10 | 10 | 10 | 9 |
检测错误行拷贝 | 10 | 0 | 10 | 9 |
分类直接对整数取前五名 | 30 | 0 | 0 | 30 |
检测使用单一scale | 10 | 0 | 0 | 9 |
检测错误拉伸坐标 | 10 | 0 | 0 | 9 |
截短原始输出文件 | 2 | 0 | 2 | 0 |
其中,行拷贝错误没有改输入文件,所以输入文件检查通过,原始输出检查却发现了变化。截短文件还触发结构告警;结果JSON未改,所以只看最终结果仍会通过。
分类整数排序的30份前五名都与正确解码不同,其中第一名变化的是此前记录过的9份。比较完整前五名与只比较第一名,是两个不同范围。
五、为什么有两例错误没有告警?
十张检测图片中,有一张正常基线本来就没有超过阈值的框。错误的scale或坐标公式作用到空列表后,结果仍然是空列表;输入与模型原始输出又没改,检查器就看不到变化。
这提醒我,检查规则之外还要考虑样本:想检查坐标换算,至少要有检测框;想覆盖不对称补边,就需要能走到该路径的图片。只拿一个空结果验收,无法证明后处理公式正确。
汇总结果是:40个正常案例没有告警,81个故障配置或文件损坏中79个告警。这个数字描述本轮已知案例的覆盖,不是未知故障检出率。
检查器也不评价参考本身是否科学正确。如果基准与当前程序都使用了同一种错误预处理,两边仍可能一致。因此第一次基准必须有明确来源和独立核对。
六、读者怎样下载和试用?
离线检查需要Python 3.11或更新版本,只使用标准库,不需要SDK或开发板:
第一条预期3/3通过。再运行包含主动修改的演示:
第二条预期3/10通过,7例告警并返回1;打开报告,可以查看每例在哪一层变化。再次运行时换一个新的报告文件名。
用于自己的工程时,换成自己的真实模型和已核对基准,再由实际执行程序记录退出码与产物路径。仓库README提供记录格式和原图片入口的捕获接入说明。
这份工具的价值,是把每次改代码后的重复核对变成一条能执行、能返回失败状态的命令。变化发生在哪一层,先有记录,再去排查;发现了变化也不自动等于新版本错误,需要结合修改目的判断。
参考资料
- 仓库 regression_tool/evidence 中的121例覆盖表、固定基准和新的板端进程捕获汇总。
