EmergentTwilight's picture
download
raw
4.86 kB
"""Project an existing fixed ThinkMorph split onto a newly encoded cache."""
from __future__ import annotations
import json
import shutil
import tempfile
from collections import Counter
from pathlib import Path
from .split_validation import EXPECTED_COUNTS, file_hash
def _rows(path: Path) -> list[dict]:
return [json.loads(line) for line in path.read_text().splitlines() if line]
def reuse_split_view(
source_cache: Path,
assignment_view: Path,
output: Path,
*,
expected_task_counts: dict[str, int] = EXPECTED_COUNTS,
expected_split_counts: dict[str, int] = {
"train": 23741,
"validation": 1249,
},
) -> dict:
source_cache, assignment_view, output = map(
lambda path: path.resolve(), (source_cache, assignment_view, output)
)
if (output / "READY").is_file():
report = json.loads((output / "SPLIT.json").read_text())
if file_hash(output / "manifest.jsonl") != report["manifest_sha256"]:
raise ValueError("existing projected split manifest hash differs")
return report
if output.exists():
raise FileExistsError(f"incomplete projected split exists: {output}")
for root in (source_cache, assignment_view):
if not (root / "READY").is_file():
raise ValueError(f"cache/view is incomplete: {root}")
source_manifest = source_cache / "manifest.jsonl"
assignment_manifest = assignment_view / "manifest.jsonl"
source_rows = _rows(source_manifest)
assignment_rows = {
row["sample_id"]: row for row in _rows(assignment_manifest)
}
if len(source_rows) != len(assignment_rows) or {
row["sample_id"] for row in source_rows
} != set(assignment_rows):
raise ValueError("new cache and assignment view have different sample IDs")
if dict(Counter(row["config"] for row in source_rows)) != expected_task_counts:
raise ValueError("new cache task counts differ")
if any(row["split"] != "train" for row in source_rows):
raise ValueError("projected view requires an all-train source cache")
projected = []
for source in source_rows:
assignment = assignment_rows[source["sample_id"]]
for key in ("config", "source"):
if source[key] != assignment[key]:
raise ValueError(
f"split provenance differs for {source['sample_id']}: {key}"
)
projected.append(
{
**source,
"source_group_id": source["group_id"],
"group_id": assignment["group_id"],
"split": assignment["split"],
"split_score": assignment["split_score"],
"cache_shard": str(
(source_cache / source["cache_shard"]).resolve()
),
}
)
counts = dict(Counter(row["split"] for row in projected))
if counts != expected_split_counts:
raise ValueError(f"projected split counts differ: {counts}")
output.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory(prefix=".grid16-idval5-", dir=output.parent) as temporary:
staging = Path(temporary) / "view"
staging.mkdir()
with (staging / "manifest.jsonl").open("w") as stream:
for row in projected:
stream.write(json.dumps(row, ensure_ascii=False) + "\n")
shutil.copyfile(
assignment_view / "image_groups.jsonl",
staging / "image_groups.jsonl",
)
config = json.loads((source_cache / "config.json").read_text())
config["split_policy"] = "reuse_fixed_assignment_v1"
config["development_view"] = {
"source_cache": str(source_cache),
"assignment_view": str(assignment_view),
"validation_fraction": 0.05,
}
report = {
"format": "thinkmorph_reused_id_validation_v1",
"rows": len(projected),
"counts": counts,
"source_cache": str(source_cache),
"source_manifest_sha256": file_hash(source_manifest),
"assignment_view": str(assignment_view),
"assignment_manifest_sha256": file_hash(assignment_manifest),
"image_groups_sha256": file_hash(staging / "image_groups.jsonl"),
"assignment_preserved": True,
"sample_id_and_source_provenance_preserved": True,
}
report["manifest_sha256"] = file_hash(staging / "manifest.jsonl")
for filename, value in (("config.json", config), ("SPLIT.json", report)):
(staging / filename).write_text(
json.dumps(value, ensure_ascii=False, indent=2) + "\n"
)
(staging / "READY").write_text("complete\n")
staging.rename(output)
return report
__all__ = ["reuse_split_view"]

Xet Storage Details

Size:
4.86 kB
·
Xet hash:
bb61f264753129d1d80784ad848bdece1a9eddc8a08fb93d7fc27e32080de681

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.