refactor: prepare_label_studio.py 的内容改动(补上 a3e08a9 漏掉的部分)
a3e08a9 只提交了 git mv 的改名,内容修改因 git add 的路径报错没有进入暂存区。
本提交补上:
- 缺省输出 runs/<source>_label_studio/,不再写到 data/;该目录同时是 Label Studio
的 DOCUMENT_ROOT,打印的导入步骤里提醒复核期间不要删除或 --overwrite。
- 总是生成 tasks.json 与 labeling config,去掉 --label-studio 开关。
- 不再写 data.yaml:复核材料不是训练集,没有 data.yaml 就不会被误拿去训练,
原先"train 与 val 相同"的告警也随之移除(detect.py 里的同类告警保留)。
- detect.py、configs/detect/film.yaml、README 里对旧脚本的引用改为新流程。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a3e08a9bbc
commit
891f930de2
@@ -589,15 +589,18 @@ runs/<name>/
|
||||
|
||||
## 检测模型训练(YOLO)
|
||||
|
||||
上一步的产出按类别分目录,方便人工核对;YOLO 的类别写在标签第一列,不靠目录名。
|
||||
所以先拍平整理,导入 Label Studio 复核,再训练:
|
||||
`generate_boxes.py` 产出的是弱监督框,要先在 Label Studio 里人工修正,再划分 train/val 训练:
|
||||
|
||||
```bash
|
||||
# 1) 拍平类别目录、统一 PNG、按类别重命名,硬链接到 data/;同时生成 Label Studio 任务
|
||||
uv run python scripts/prepare_yolo_dataset.py --source runs/boxes_shap --label-studio
|
||||
# 1) 生成 Label Studio 复核材料到 runs/boxes_shap_label_studio/
|
||||
uv run python scripts/prepare_label_studio.py --source runs/boxes_shap
|
||||
# 先看计划加 --dry-run
|
||||
|
||||
# 2) 训练(训练前需要先划分,见下文"不划分 train/val")
|
||||
# 2) 在 Label Studio 里修正标签(导入步骤见下文,脚本结束时也会打印)
|
||||
|
||||
# 3) 导出修好的标签,划分 train/val 到 data/boxes_shap/(导出脚本待写)
|
||||
|
||||
# 4) 训练
|
||||
uv run python detect.py --config configs/detect/film.yaml
|
||||
|
||||
# 只评估 / 续训
|
||||
@@ -606,27 +609,26 @@ uv run python detect.py --config configs/detect/film.yaml --eval-only \
|
||||
uv run python detect.py --config configs/detect/film.yaml --resume
|
||||
```
|
||||
|
||||
产出:
|
||||
### 准备 Label Studio 复核材料
|
||||
|
||||
```
|
||||
data/boxes_shap/
|
||||
runs/boxes_shap_label_studio/ # 同时也是 Label Studio 的 DOCUMENT_ROOT
|
||||
├── images/<类别>_<序号>.png # 一律 PNG:PNG 原图硬链接,BMP 等无损转换
|
||||
├── labels/<类别>_<序号>.txt
|
||||
├── classes.txt # 每行一个类别名,行号即 class_id
|
||||
├── name_map.csv # 新文件名 ↔ 源文件路径
|
||||
├── data.yaml # train 与 val 都指向 images/
|
||||
├── summary.json # 逐类数量、空标签处置、落盘方式
|
||||
├── tasks.json # 仅 --label-studio:每张图一个任务,框作为 predictions
|
||||
└── tasks.label_config.xml # 仅 --label-studio:各类别的 RectangleLabels
|
||||
├── tasks.json # 每张图一个任务,框作为 predictions
|
||||
└── tasks.label_config.xml # 各类别的 RectangleLabels
|
||||
```
|
||||
|
||||
**不划分 train/val。** 这份数据集先导入 Label Studio 复核,划分留到复核之后。`data.yaml`
|
||||
的 `train` 与 `val` 只能指向同一个 `images/`,ultralytics 能读,但验证指标算的是训练集本身,
|
||||
mAP 会虚高,早停与 `best.pt` 的选择也随之失真。脚本结束时会告警,`detect.py` 检测到
|
||||
train 与 val 相同时也会告警。正式训练前要先划分。
|
||||
**不写 `data.yaml`、不划分 train/val。** 这是给人复核的材料,不是训练集,没有 `data.yaml`
|
||||
也就不会被误拿去训练。复核期间 Label Studio 直接从这个目录读图,**不要删除或 `--overwrite` 它**。
|
||||
`detect.py` 若检测到 `data.yaml` 的 train 与 val 相同(`generate_boxes.py` 的产出就是这样),
|
||||
也会告警:验证指标算的是训练集本身,mAP 虚高,早停与 `best.pt` 的选择失真。
|
||||
|
||||
**图片统一成 PNG。** pearlescent / blue / uv 的原始数据是 BMP(共 10,814 张),
|
||||
`generate_boxes.py` 按原后缀链接,于是 YOLO 数据集里会混着两种格式。这一步按**文件头**
|
||||
`generate_boxes.py` 按原后缀链接,于是产出里混着两种格式。这一步按**文件头**
|
||||
(不是后缀)判断:真 PNG 照旧硬链接不占磁盘,其余无损转 PNG——不缩放像素,归一化的框坐标
|
||||
原样有效;CMYK 这类 PNG 存不下的模式转 RGB。转换无法硬链接,会占额外磁盘,`--dry-run`
|
||||
会先报出要转多少张。统一后缀后 `a.png` 与另一目录的 `a.bmp` 会撞名,脚本直接报错。
|
||||
@@ -634,16 +636,13 @@ train 与 val 相同时也会告警。正式训练前要先划分。
|
||||
**按类别重新编号。** 源文件名五花八门(`反面纵黑点_1_550mmX1561.71m_20260416160441_0.png`、
|
||||
`pearlescent_404.bmp`……),输出统一改成 `<类别>_<序号>.png`,如 `blackdot_0042.png`。
|
||||
类别以标签第一列为准,文件名永远不会与标签矛盾;序号在类内按源路径排序,同一份来源重跑,
|
||||
同一张图拿到的名字不变。原文件名里的正反面、位置、
|
||||
时间戳等信息都在 `name_map.csv` 里(带 BOM,Excel 直接打开中文不乱码)。想保留原名加 `--keep-names`。
|
||||
同一张图拿到的名字不变。原文件名里的正反面、位置、时间戳等信息都在 `name_map.csv` 里
|
||||
(带 BOM,Excel 直接打开中文不乱码)。想保留原名加 `--keep-names`。
|
||||
|
||||
**classes.txt** 是给 LabelImg / X-AnyLabeling 这类标注工具用的,人工复核、修改框时
|
||||
靠它把 class_id 映射回类别名;ultralytics 训练本身只读 `data.yaml`,两者内容严格一致。
|
||||
**classes.txt** 是 label-studio-converter 读类别用的(也兼容 LabelImg / X-AnyLabeling),
|
||||
行号就是 class_id,内容与来源 `data.yaml` 严格一致。
|
||||
|
||||
### 导入 Label Studio 人工复核
|
||||
|
||||
弱监督框需要人工把关。加 `--label-studio` 会在数据集根目录额外生成 `tasks.json` 与
|
||||
`tasks.label_config.xml`,数据集根目录本身就是 Label Studio 的 `DOCUMENT_ROOT`。
|
||||
### 导入 Label Studio
|
||||
|
||||
脚本结束时会打印带实际路径的导入步骤:设置 `LABEL_STUDIO_LOCAL_FILES_*` 环境变量启动、
|
||||
粘贴 labeling config、添加 Local files 存储(**只保存不要 Sync**,否则每张图多出一个空任务)、
|
||||
@@ -652,7 +651,7 @@ train 与 val 相同时也会告警。正式训练前要先划分。
|
||||
几个取舍:
|
||||
|
||||
- **为什么是扁平结构**:`label-studio-converter import yolo` 只认 `<input>/{images,labels,classes.txt}`,
|
||||
且 `os.listdir` 不递归,看不见子目录。数据集不划分、直接扁平,正好就是它要的结构。
|
||||
且 `os.listdir` 不递归,看不见子目录。
|
||||
- **硬链接而不是软链接**:Label Studio 读本地文件时会检查路径是否在 `DOCUMENT_ROOT` 之下,
|
||||
软链接解析后可能落到外面。
|
||||
- **框作为 predictions 而不是 annotations**:它们是模型生成的。审核员修改提交后才成为 annotation,
|
||||
@@ -686,7 +685,7 @@ Grad-CAM 没框出东西的有 339 张(占 3%)。它们**默认保留为负
|
||||
等于在教模型抑制真实缺陷。用 `--empty-policy` 按来源类别分别处置:
|
||||
|
||||
```bash
|
||||
uv run python scripts/prepare_yolo_dataset.py --source runs/boxes_gradcam \
|
||||
uv run python scripts/prepare_label_studio.py --source runs/boxes_gradcam \
|
||||
--empty-policy drop normal=keep black=full edge_clean=full
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user