feat(detect): 把弱监督框数据集链接到 data/ 并接上 YOLO 训练
第五步产出的框标签按类别分目录,便于人工核对;检测训练要的是 train/val 划分——类别写在标签第一列,不靠目录名。补上两个入口: - scripts/prepare_yolo_dataset.py:拍平类别目录、按类别分层切分、硬链接到 data/。分层是必需的,black 只有 53 张,随机切容易让小类在验证集里挂零。 无框的图默认保留(检测训练里是压低误检的负样本);拍平后的同名冲突直接 报错而不是静默覆盖。 - detect.py + configs/detect/film.yaml:包一层 ultralytics,沿用本仓库的 配置继承、设备解析与 SwanLab 可视化。 选 YOLOv8 而不是 v11/v12:CLAUDE.md 限定只用 convolution 模型,YOLO11 骨架 里有 C2PSA、YOLO12 以注意力为主,只有 v8 的 C2f + SPPF 是纯卷积。 mosaic/mixup 关掉——每张图只有一个弱监督框,拼接后小目标被缩得更小,对 blackdot/whitedot 这类只占千分之几面积的类别是净伤害。 ultralytics 的 project 必须传绝对路径,相对路径会被它再拼到全局 settings 的 runs_dir 上,产出会跑到 runs/detect/runs/detect/<name> 去。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
86c86b105c
commit
8dc2fe6a2e
@@ -587,6 +587,73 @@ runs/<name>/
|
||||
> 它们的框没有物理意义。真正有用的是 `blackdot`/`whitedot`/`mosquito`/`grease` 这些
|
||||
> 有局部目标的类别。
|
||||
|
||||
## 检测模型训练(YOLO)
|
||||
|
||||
上一步的产出按类别分目录,方便人工核对;检测训练要的是 train/val 划分——类别写在标签
|
||||
第一列,不靠目录名。所以先整理再训练:
|
||||
|
||||
```bash
|
||||
# 1) 拍平类别目录、分层切分、硬链接到 data/(不占额外磁盘)
|
||||
uv run python scripts/prepare_yolo_dataset.py --source runs/boxes_gradcam
|
||||
# 先看计划加 --dry-run
|
||||
|
||||
# 2) 训练
|
||||
uv run python detect.py --config configs/detect/film.yaml
|
||||
|
||||
# 只评估 / 续训
|
||||
uv run python detect.py --config configs/detect/film.yaml --eval-only \
|
||||
--checkpoint runs/detect/film/weights/best.pt
|
||||
uv run python detect.py --config configs/detect/film.yaml --resume
|
||||
```
|
||||
|
||||
产出:
|
||||
|
||||
```
|
||||
data/boxes_gradcam/
|
||||
├── images/{train,val}/<图名>.png # 硬链接到 runs/,再到 data/raw/ 的原图
|
||||
├── labels/{train,val}/<图名>.txt
|
||||
├── data.yaml # path 写绝对路径,ultralytics 从哪跑都能读到
|
||||
└── summary.json # 划分明细、逐类数量、链接方式
|
||||
```
|
||||
|
||||
### 划分
|
||||
|
||||
按类别分层(`--val-ratio` 默认 0.2,`--seed` 默认 42,两次运行结果一致)。分层是必需的:
|
||||
`black` 只有 53 张、`others` 69 张,随机切很容易让某个小类在验证集里挂零,指标就成了空的。
|
||||
|
||||
无框的图(Grad-CAM 没框出东西的那 339 张,占 3%)**默认保留**——在检测训练里它们是负样本,
|
||||
对压低误检有用。不要时加 `--drop-empty`。
|
||||
|
||||
拍平之后不同类别目录下的同名文件会互相覆盖,脚本会直接报错而不是静默丢数据;
|
||||
真遇上就用 `scripts/export_clusters.py --prefix-parent` 重新导出。
|
||||
|
||||
### 模型与增强的取舍
|
||||
|
||||
- **选 YOLOv8 而不是 v11/v12**:CLAUDE.md 限定只用 convolution 模型,而 YOLO11 骨架里有
|
||||
C2PSA(position-sensitive attention)、YOLO12 更是以注意力为主。YOLOv8 的 C2f + SPPF 是纯卷积。
|
||||
`s` 是精度/速度折中——数据只有 1.1 万张且标签是弱监督的,模型再大容易把标注噪声一起学进去。
|
||||
- **关掉 mosaic / mixup**:它们把四张图拼一起,而我们每张图只有一个弱监督框,拼接后小目标被
|
||||
缩得更小,对 `blackdot`/`whitedot` 这类本就只占千分之几面积的类别是净伤害。
|
||||
- **关掉 hsv_h**:薄膜图近乎单色,色相扰动没有意义。翻转照旧开着(缺陷没有固定朝向)。
|
||||
- 冒烟测试用 `--set train.epochs=1 train.fraction=0.02 train.imgsz=320` 先把链路跑通。
|
||||
|
||||
> **指标怎么读。** 框来自 Grad-CAM/SHAP 的弱监督标注,不是人工真值。mAP 衡量的是"检测器
|
||||
> 能不能复现归因热力区域",不等于"缺陷定位有多准"。真值上的精度仍需人工抽检。
|
||||
|
||||
### 可视化
|
||||
|
||||
`train.swanlab.enabled: true` 时接 SwanLab 回调,训练曲线实时可看(`swanlab watch` 开本地看板)。
|
||||
ultralytics 自己还会在 `runs/detect/film/` 下写:
|
||||
|
||||
- `results.png` / `results.csv`——各项 loss 与 mAP 曲线
|
||||
- `confusion_matrix.png`、`confusion_matrix_normalized.png`
|
||||
- `BoxPR_curve.png` / `BoxP_curve.png` / `BoxR_curve.png` / `BoxF1_curve.png`
|
||||
- `train_batch*.jpg`、`val_batch*_labels.jpg` 与 `val_batch*_pred.jpg`——标注与预测的直观对照
|
||||
- `metrics.json`——mAP50-95 / mAP50 / P / R 与逐类 mAP50
|
||||
|
||||
> **许可提醒。** ultralytics 是 AGPL-3.0。模型若要随产品分发,需要开源整套代码或另购商业授权;
|
||||
> 仅内部使用不受影响。
|
||||
|
||||
## 方法
|
||||
|
||||
- **骨架**:`tiny_conv`(自研深度可分离卷积,默认)或 `torchvision`(resnet / mobilenet / shufflenet)。
|
||||
|
||||
Reference in New Issue
Block a user