feat: train fixed-size classifiers and export class probabilities
This commit is contained in:
@@ -801,36 +801,64 @@ ultralytics 自己还会在 `runs/detect/film/` 下写:
|
||||
配置支持 `_base_` 继承与命令行 `--set a.b.c=value` 覆盖,见 [utils/config.py](utils/config.py)。
|
||||
新增骨架 / 数据集只需用注册表装饰器注册,再在 yaml 里按 `name` 引用。
|
||||
|
||||
## 分类模型复用 YOLO OpenVINO 接口
|
||||
## 分类模型导出 OpenVINO
|
||||
|
||||
生产端只使用类别时,可以将分类器导出成与既有 YOLO IR 相同的输入输出接口:
|
||||
分类器直接输出按训练类别顺序排列的 Softmax 概率,不适配 YOLO 检测输出:
|
||||
|
||||
```bash
|
||||
uv pip install openvino
|
||||
uv run python scripts/export_classifier_openvino.py \
|
||||
--checkpoint runs/classify/best.pth \
|
||||
--template runs/detect/models/film_128_20261013_0902_openvino_model/film_128_20261013_0902.xml \
|
||||
--out runs/classify/models/resnet18_128_yolo_adapter
|
||||
--fp32-weights --out runs/classify/models/resnet18_128_probabilities
|
||||
```
|
||||
|
||||
`--template` 请指定实际部署的 YOLO `.xml`,其同目录需要有 `metadata.yaml`。
|
||||
脚本读取分类检查点的配置和同目录 `eval_report.json` 中的类别顺序;也可用
|
||||
`--classes classes.txt` 或 `--classes eval_report.json` 明确指定分类器的类别顺序。
|
||||
两者类别集合不一致、训练预处理不受支持或输入尺寸不匹配时会拒绝导出。
|
||||
指定顺序不能与检查点记录矛盾。输入尺寸从检查点读取,不依赖 YOLO 模型。
|
||||
|
||||
产出的 XML/BIN 使用模板文件名,输入为 RGB float32 BCHW、值域 `[0,1]`。
|
||||
逐图标准化按训练配置嵌入模型,分类概率按 YOLO 类别顺序排列。
|
||||
输出保持 `[1,4+nc,anchors]`:仅第一个候选携带全图伪框及 Softmax 概率,其他候选为零。
|
||||
伪框是像素 `cx,cy,w,h`,不表示缺陷位置。脚本不进行 resize,图片必须已切为目标尺寸。
|
||||
产出的 XML/BIN 按骨架命名,如 `resnet18.xml/.bin`、`mobilenet_v3_small.xml/.bin`。
|
||||
输入为 RGB float32 BCHW、值域 `[0,1]`,输入名为 `images`。
|
||||
逐图标准化仅在训练配置使用时嵌入模型。脚本不进行 resize,图片必须已切为目标尺寸。
|
||||
输出名为 `probabilities`,形状 `[1,C]`:九类模型是 `[1,9]`,索引直接对应 `classes.txt`。
|
||||
每类概率在 `[0,1]` 内,概率和为 1;normal 也返回真实概率,不清零、不做阈值过滤。
|
||||
|
||||
部署时成对替换 XML/BIN;使用元数据的程序也需同步 `metadata.yaml`。
|
||||
仓库的 `deploy/cpp` 解码器可直接读取适配模型,生产代码若有额外硬编码则需核对。
|
||||
Softmax 分数不同于 YOLO 置信度,需在实际数据上确认过滤阈值。
|
||||
默认 top1 为 `normal` 时,所有候选类别分数清零,C++ 在正数置信度阈值下返回空列表,
|
||||
与 YOLO 的背景行为一致。类别编号保持不变,`normal` 仍占其原通道。
|
||||
用 `--background-class` 指定其他背景类别,或 `--keep-background-box` 恢复普通分类输出。
|
||||
原图被切成多片时,每片独立分类,仅前景片返回伪框。
|
||||
部署端直接对 C 个概率取 argmax;normal 是否表示正常、是否应用阈值由业务层决定。
|
||||
现有 `deploy/cpp` 是 YOLO 框解码器,不能用于此分类输出;需要按 `[1,C]` 读取,
|
||||
不要跳过前四个通道或遍历候选框。模型附带 `metadata.yaml`、`classes.txt` 和 `export.json`。
|
||||
输出目录必须是新目录,原有模型不会被覆盖。
|
||||
默认压缩权重为 FP16;需要优先核对转换前后判别一致性时,加 `--fp32-weights`
|
||||
保留 FP32 权重,减少分类边界处的舍入差异。输入输出接口仍是 float32。
|
||||
|
||||
### 在固定 128×128 YOLO 裁片上监督训练分类器
|
||||
|
||||
```bash
|
||||
uv run python classify.py --config configs/classify/film_tiles128_resnet18.yaml \
|
||||
--work-dir runs/classify_tiles128_resnet18
|
||||
uv run python classify.py --config configs/classify/film_tiles128_mobilenet_v3_small.yaml \
|
||||
--work-dir runs/classify_tiles128_mobilenet_v3_small
|
||||
```
|
||||
|
||||
数据从 `data/film_yolo_128/data.yaml` 读取,保留现有 train/val 划分和类别编号。
|
||||
监督标签来自 YOLO 标注文件,空标签表示 normal;多类别裁片取面积最大的框对应类别。
|
||||
缺失标签文件会报错,不会自动当背景。图片必须已经是 128×128 PNG,禁止 resize。
|
||||
这两份配置使用 RGB / 255,与检测部署输入一致;不进行逐图标准化。
|
||||
最佳权重按验证 macro-F1 保存,可用上述导出脚本生成 OpenVINO 分类概率模型。
|
||||
分类准确率、转换前后一致率和与 YOLO 的一致率是不同指标,应分别报告。
|
||||
|
||||
导出后,在同一固定裁片验证集上检查这三个指标(示例):
|
||||
|
||||
```bash
|
||||
uv run python scripts/compare_openvino_classes.py \
|
||||
--teacher runs/detect/models/film_128_20261013_0902_openvino_model/film_128_20261013_0902.xml \
|
||||
--student runs/classify/models/resnet18_tiles128/resnet18.xml \
|
||||
--checkpoint runs/classify_tiles128_resnet18/best.pth \
|
||||
--conf 0.25 --report runs/classify_tiles128_resnet18/comparison.json
|
||||
```
|
||||
|
||||
`--student` 指向实际导出的 XML。这里 `--teacher` 只用于比较,不参与训练。
|
||||
YOLO 有有效框时取最高分候选的类别,无有效框记为 normal。比较工具在业务层对分类概率
|
||||
使用同一置信度阈值,低于阈值时记为 normal;模型本身仍返回全部真实概率。
|
||||
报告同时记录各类支持数、总体/前景一致率和逐图结果。
|
||||
|
||||
## 开发
|
||||
|
||||
|
||||
Reference in New Issue
Block a user