2026-05-25 16:59:59 +08:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
"""按 workflow active_packs 生成 manifests/yaml_active/*.yaml(可多包合并 train/val)。"""
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
|
|
import sys
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
|
|
|
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
|
|
|
|
sys.path.insert(0, str(SCRIPT_DIR))
|
2026-06-03 11:40:21 +08:00
|
|
|
|
from pack_registry import load_active_pack_names, resolve_pack_dir # noqa: E402
|
|
|
|
|
|
from task_registry import get_mode_config, load_registry, train_yaml_key # noqa: E402
|
2026-05-25 16:59:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fmt_names(names) -> str:
|
|
|
|
|
|
if isinstance(names, dict):
|
|
|
|
|
|
lines = ["names:"]
|
|
|
|
|
|
for k, v in sorted(names.items(), key=lambda x: int(x[0])):
|
|
|
|
|
|
lines.append(f" {k}: {v}")
|
|
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
inner = ", ".join(f'"{n}"' for n in names)
|
|
|
|
|
|
return f"names: [{inner}]"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def yaml_list(key: str, paths: list[str]) -> str:
|
|
|
|
|
|
if len(paths) == 1:
|
|
|
|
|
|
return f"{key}: {paths[0]}"
|
|
|
|
|
|
lines = [f"{key}:"] + [f" - {p}" for p in paths]
|
|
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pack_task_root(root: Path, pack_name: str, task_dir: str) -> Path:
|
|
|
|
|
|
return resolve_pack_dir(root, pack_name) / task_dir
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_detect_pose_yaml(
|
2026-06-03 11:40:21 +08:00
|
|
|
|
yaml_key: str,
|
|
|
|
|
|
mcfg: dict,
|
2026-05-25 16:59:59 +08:00
|
|
|
|
root: Path,
|
|
|
|
|
|
pack_names: list[str],
|
|
|
|
|
|
typ: str,
|
|
|
|
|
|
) -> str:
|
2026-06-03 11:40:21 +08:00
|
|
|
|
task_dir = mcfg["task_dir"]
|
2026-05-25 16:59:59 +08:00
|
|
|
|
bases = []
|
|
|
|
|
|
train_paths = []
|
|
|
|
|
|
val_paths = []
|
|
|
|
|
|
for pack in pack_names:
|
|
|
|
|
|
base = pack_task_root(root, pack, task_dir)
|
|
|
|
|
|
if not base.is_dir():
|
|
|
|
|
|
print(f" skip pack {pack}: missing {base}")
|
|
|
|
|
|
continue
|
|
|
|
|
|
bases.append(base)
|
|
|
|
|
|
train_paths.append(str((base / "images" / "train").resolve()))
|
|
|
|
|
|
val_paths.append(str((base / "images" / "val").resolve()))
|
|
|
|
|
|
|
|
|
|
|
|
if not bases:
|
2026-06-03 11:40:21 +08:00
|
|
|
|
raise SystemExit(f"{yaml_key}: 无可用数据包目录")
|
2026-05-25 16:59:59 +08:00
|
|
|
|
|
|
|
|
|
|
lines = [
|
2026-06-03 11:40:21 +08:00
|
|
|
|
f"# {yaml_key} — packs: {', '.join(pack_names)}",
|
2026-05-25 16:59:59 +08:00
|
|
|
|
f"path: {bases[0]}",
|
|
|
|
|
|
yaml_list("train", train_paths),
|
|
|
|
|
|
yaml_list("val", val_paths),
|
|
|
|
|
|
"",
|
|
|
|
|
|
]
|
|
|
|
|
|
if typ == "pose":
|
2026-06-03 11:40:21 +08:00
|
|
|
|
lines.insert(4, f"kpt_shape: {mcfg.get('kpt_shape', [37, 3])}")
|
2026-05-25 16:59:59 +08:00
|
|
|
|
else:
|
2026-06-03 11:40:21 +08:00
|
|
|
|
lines.extend([f"nc: {mcfg['nc']}", fmt_names(mcfg["names"]), ""])
|
2026-05-25 16:59:59 +08:00
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-03 11:40:21 +08:00
|
|
|
|
def build_classify_yaml(yaml_key: str, mcfg: dict, root: Path, pack_names: list[str]) -> str:
|
|
|
|
|
|
task_dir = mcfg["task_dir"]
|
2026-05-25 16:59:59 +08:00
|
|
|
|
if len(pack_names) > 1:
|
2026-06-03 11:40:21 +08:00
|
|
|
|
print(f" warn {yaml_key}: classify 暂用首个包 {pack_names[0]}(多包请先合并目录)")
|
2026-05-25 16:59:59 +08:00
|
|
|
|
base = pack_task_root(root, pack_names[0], task_dir)
|
2026-06-03 11:40:21 +08:00
|
|
|
|
return f"""# {yaml_key} — pack: {pack_names[0]}
|
2026-05-25 16:59:59 +08:00
|
|
|
|
path: {base.resolve()}
|
|
|
|
|
|
train: train
|
|
|
|
|
|
val: val
|
|
|
|
|
|
test: test
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-03 11:40:21 +08:00
|
|
|
|
def iter_yaml_jobs(reg: dict, only_task: str | None = None):
|
|
|
|
|
|
tasks = load_registry(reg)
|
|
|
|
|
|
if only_task:
|
|
|
|
|
|
if only_task not in tasks:
|
|
|
|
|
|
raise SystemExit(f"未知 task: {only_task}")
|
|
|
|
|
|
tasks = {only_task: tasks[only_task]}
|
|
|
|
|
|
for task, tcfg in tasks.items():
|
|
|
|
|
|
if tcfg.get("type") == "multi":
|
|
|
|
|
|
for mode in (tcfg.get("modes") or {}):
|
|
|
|
|
|
mcfg = get_mode_config(task, mode, reg)
|
|
|
|
|
|
key = train_yaml_key(task, mode, reg)
|
|
|
|
|
|
yield key, mcfg
|
|
|
|
|
|
else:
|
|
|
|
|
|
yield task, tcfg
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-25 16:59:59 +08:00
|
|
|
|
def main() -> None:
|
|
|
|
|
|
p = argparse.ArgumentParser()
|
|
|
|
|
|
p.add_argument("--root", type=Path, default=SCRIPT_DIR.parent)
|
|
|
|
|
|
p.add_argument("--packs", help="逗号分隔,覆盖 workflow active_packs")
|
2026-06-03 11:40:21 +08:00
|
|
|
|
p.add_argument("--task", help="只生成某一任务(multi 会生成全部 mode)")
|
2026-05-25 16:59:59 +08:00
|
|
|
|
args = p.parse_args()
|
|
|
|
|
|
root = args.root.resolve()
|
|
|
|
|
|
reg = yaml.safe_load((root / "datasets.registry.yaml").read_text(encoding="utf-8"))
|
|
|
|
|
|
cli = [x.strip() for x in args.packs.split(",")] if args.packs else None
|
|
|
|
|
|
pack_names = load_active_pack_names(root, cli)
|
|
|
|
|
|
if not pack_names:
|
2026-06-03 11:40:21 +08:00
|
|
|
|
raise SystemExit("active_packs 为空,请编辑 workflow.registry.yaml 或 --packs")
|
2026-05-25 16:59:59 +08:00
|
|
|
|
|
|
|
|
|
|
out_dir = root / "manifests" / "yaml_active"
|
|
|
|
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
print(f"active_packs: {pack_names}")
|
|
|
|
|
|
|
2026-06-03 11:40:21 +08:00
|
|
|
|
for yaml_key, mcfg in iter_yaml_jobs(reg, args.task):
|
|
|
|
|
|
typ = mcfg["type"]
|
2026-05-25 16:59:59 +08:00
|
|
|
|
if typ in ("detect", "pose"):
|
2026-06-03 11:40:21 +08:00
|
|
|
|
content = build_detect_pose_yaml(yaml_key, mcfg, root, pack_names, typ)
|
2026-05-25 16:59:59 +08:00
|
|
|
|
elif typ == "classify":
|
2026-06-03 11:40:21 +08:00
|
|
|
|
content = build_classify_yaml(yaml_key, mcfg, root, pack_names)
|
2026-05-25 16:59:59 +08:00
|
|
|
|
else:
|
2026-06-03 11:40:21 +08:00
|
|
|
|
print(f" skip {yaml_key}: type {typ}")
|
2026-05-25 16:59:59 +08:00
|
|
|
|
continue
|
2026-06-03 11:40:21 +08:00
|
|
|
|
out = out_dir / f"{yaml_key}.yaml"
|
2026-05-25 16:59:59 +08:00
|
|
|
|
out.write_text(content, encoding="utf-8")
|
|
|
|
|
|
print(f" wrote {out.relative_to(root)}")
|
|
|
|
|
|
|
|
|
|
|
|
print("完成。")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
main()
|