make building results authority-first after V74 evaluation
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compose legacy rehearsal and fresh remediation tiles for an experiment."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
if str(SCRIPT_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPT_DIR))
|
||||
|
||||
from export_experimental_yolo_train_shard import EXPERIMENTAL_ROOT, file_sha256 # noqa: E402
|
||||
|
||||
|
||||
def _inside(path: Path, root: Path) -> bool:
|
||||
try:
|
||||
path.resolve().relative_to(root.resolve())
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def validate_sources(rehearsal_summary: Path, remediation_summary: Path, output_dir: Path) -> tuple[dict, dict]:
|
||||
if not _inside(output_dir, EXPERIMENTAL_ROOT):
|
||||
raise ValueError(f"output must remain below {EXPERIMENTAL_ROOT}")
|
||||
rehearsal = json.loads(rehearsal_summary.read_text(encoding="utf-8"))
|
||||
remediation = json.loads(remediation_summary.read_text(encoding="utf-8"))
|
||||
marker_path = remediation_summary.parent / "EXPERIMENTAL_ONLY.json"
|
||||
if not marker_path.is_file():
|
||||
raise ValueError("fresh remediation source has no EXPERIMENTAL_ONLY marker")
|
||||
marker = json.loads(marker_path.read_text(encoding="utf-8"))
|
||||
if marker.get("promotion_allowed") is not False:
|
||||
raise ValueError("fresh remediation marker does not prohibit promotion")
|
||||
if remediation.get("source_manifest_sha256") != marker.get("source_manifest_sha256"):
|
||||
raise ValueError("fresh remediation marker/summary binding mismatch")
|
||||
rehearsal_tiles = [tile for tile in rehearsal.get("tiles") or [] if tile.get("kept", True)]
|
||||
remediation_tiles = [tile for tile in remediation.get("tiles") or [] if tile.get("kept", True)]
|
||||
if not rehearsal_tiles or not remediation_tiles:
|
||||
raise ValueError("both rehearsal and remediation summaries require retained tiles")
|
||||
if any(tile.get("split") not in {"train", "val"} for tile in rehearsal_tiles):
|
||||
raise ValueError("rehearsal source contains a protected or unsupported split")
|
||||
if any(tile.get("split") != "train" for tile in remediation_tiles):
|
||||
raise ValueError("fresh remediation source must be train-only")
|
||||
return rehearsal, remediation
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--rehearsal-summary", type=Path, required=True)
|
||||
parser.add_argument("--remediation-summary", type=Path, required=True)
|
||||
parser.add_argument("--output-dir", type=Path, required=True)
|
||||
parser.add_argument("--remediation-repeat", type=int, default=2)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
if args.remediation_repeat < 1 or args.remediation_repeat > 4:
|
||||
raise SystemExit("remediation-repeat must be between 1 and 4")
|
||||
if args.output_dir.exists():
|
||||
raise SystemExit(f"refusing to overwrite rehearsal dataset: {args.output_dir}")
|
||||
try:
|
||||
rehearsal, remediation = validate_sources(
|
||||
args.rehearsal_summary, args.remediation_summary, args.output_dir
|
||||
)
|
||||
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
||||
raise SystemExit(str(exc)) from exc
|
||||
rehearsal_yaml = Path(str(rehearsal["dataset_yaml"]))
|
||||
remediation_yaml = Path(str(remediation["dataset_yaml"]))
|
||||
rehearsal_root = rehearsal_yaml.parent
|
||||
remediation_root = remediation_yaml.parent
|
||||
for directory in (
|
||||
rehearsal_root / "images" / "train",
|
||||
rehearsal_root / "images" / "val",
|
||||
remediation_root / "images" / "train",
|
||||
):
|
||||
if not directory.is_dir():
|
||||
raise SystemExit(f"rehearsal dataset directory is missing: {directory}")
|
||||
args.output_dir.mkdir(parents=True)
|
||||
train_sources = [str(rehearsal_root / "images" / "train")] + [
|
||||
str(remediation_root / "images" / "train")
|
||||
] * args.remediation_repeat
|
||||
yaml_path = args.output_dir / "dataset.yaml"
|
||||
yaml_path.write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"path: /",
|
||||
"train:",
|
||||
*[f" - {path}" for path in train_sources],
|
||||
f"val: {rehearsal_root / 'images' / 'val'}",
|
||||
"names:",
|
||||
" 0: building",
|
||||
"",
|
||||
]
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
summary = {
|
||||
"schema_version": 1,
|
||||
"status": "experimental_rehearsal_only",
|
||||
"promotion_allowed": False,
|
||||
"release_claim_allowed": False,
|
||||
"human_review_pending": True,
|
||||
"dataset_yaml": str(yaml_path),
|
||||
"dataset_yaml_sha256": file_sha256(yaml_path),
|
||||
"rehearsal_summary": str(args.rehearsal_summary),
|
||||
"rehearsal_summary_sha256": file_sha256(args.rehearsal_summary),
|
||||
"remediation_summary": str(args.remediation_summary),
|
||||
"remediation_summary_sha256": file_sha256(args.remediation_summary),
|
||||
"remediation_repeat": args.remediation_repeat,
|
||||
"rehearsal_train_tile_count": int(rehearsal.get("train_tile_count") or 0),
|
||||
"remediation_unique_train_tile_count": int(remediation.get("tile_count") or 0),
|
||||
"protected_v72_used": False,
|
||||
}
|
||||
(args.output_dir / "experimental_rehearsal_summary.json").write_text(
|
||||
json.dumps(summary, indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||
)
|
||||
marker = {
|
||||
key: summary[key]
|
||||
for key in (
|
||||
"schema_version",
|
||||
"status",
|
||||
"promotion_allowed",
|
||||
"release_claim_allowed",
|
||||
"dataset_yaml_sha256",
|
||||
"rehearsal_summary_sha256",
|
||||
"remediation_summary_sha256",
|
||||
)
|
||||
}
|
||||
(args.output_dir / "EXPERIMENTAL_ONLY.json").write_text(
|
||||
json.dumps(marker, indent=2, sort_keys=True) + "\n", encoding="utf-8"
|
||||
)
|
||||
print(json.dumps(summary, indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user