Balance YOLO label QA coverage
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-07-12 23:53:18 +02:00
parent 0f49c980ba
commit 3266c6578d
6 changed files with 117 additions and 9 deletions
@@ -120,6 +120,33 @@ def tile_sort_key(tile: dict[str, Any]) -> tuple[int, str, str, int, int]:
)
def balanced_tiles_by_sample(tiles: list[dict[str, Any]], limit: int) -> list[dict[str, Any]]:
if limit <= 0 or not tiles:
return []
grouped: dict[str, list[dict[str, Any]]] = {}
for tile in tiles:
grouped.setdefault(str(tile.get("sample_slug") or "unknown"), []).append(tile)
for sample_tiles in grouped.values():
sample_tiles.sort(key=tile_sort_key)
sample_order = sorted(grouped, key=lambda slug: tile_sort_key(grouped[slug][0]))
selected: list[dict[str, Any]] = []
depth = 0
while len(selected) < limit:
added = False
for slug in sample_order:
sample_tiles = grouped[slug]
if depth < len(sample_tiles):
selected.append(sample_tiles[depth])
added = True
if len(selected) == limit:
break
if not added:
break
depth += 1
return selected
def select_tiles(tiles: list[dict[str, Any]], max_tiles: int) -> list[dict[str, Any]]:
if max_tiles <= 0:
raise ValueError("max_tiles must be positive")
@@ -135,7 +162,8 @@ def select_tiles(tiles: list[dict[str, Any]], max_tiles: int) -> list[dict[str,
)
negative_slots = min(len(negatives), max(1, max_tiles // 5)) if negatives and max_tiles > 1 else 0
selected = positives[: max_tiles - negative_slots] + negatives[:negative_slots]
selected = balanced_tiles_by_sample(positives, max_tiles - negative_slots)
selected.extend(balanced_tiles_by_sample(negatives, negative_slots))
if len(selected) < max_tiles:
selected_ids = {id(tile) for tile in selected}
@@ -302,6 +330,12 @@ def build_report(summary: dict[str, Any], summary_path: Path, args: argparse.Nam
"columns": args.columns,
"thumb_size": args.thumb_size,
"selected_tile_count": len(selected_tiles),
"selected_sample_count": len(
{str(tile.get("sample_slug") or "unknown") for tile in selected_tiles}
),
"selected_sample_slugs": sorted(
{str(tile.get("sample_slug") or "unknown") for tile in selected_tiles}
),
"rendered_tile_count": len(rendered_cards),
"missing_image_count": missing_image_count,
"missing_label_file_count": missing_label_file_count,
@@ -322,6 +356,7 @@ def write_markdown(report: dict[str, Any], output_dir: Path) -> None:
"",
f"- status: `{report['status']}`",
f"- selected tiles: {report['selected_tile_count']}",
f"- selected source samples: {report['selected_sample_count']}",
f"- rendered tiles: {report['rendered_tile_count']}",
f"- missing images: {report['missing_image_count']}",
f"- missing label files: {report['missing_label_file_count']}",