CoVT-H20-Repro-Checkpoints / h20_context /scripts /03_materialize_covt_dataset.py
Steven668866's picture
Migrate H20 CoVT checkpoint archive to Steven668866
d0f5e0c verified
Raw
History Blame Contribute Delete
3.82 kB
#!/usr/bin/env python3
import argparse
import json
import os
import re
import time
from pathlib import Path
import pyarrow.parquet as pq
def safe_name(value: str, fallback: str) -> str:
name = Path(value or fallback).name or fallback
name = re.sub(r"[^A-Za-z0-9._-]+", "_", name)
return name or fallback
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--dataset-dir", required=True)
parser.add_argument("--image-root", required=True)
parser.add_argument("--json-out", required=True)
parser.add_argument("--batch-size", type=int, default=512)
parser.add_argument("--progress-every", type=int, default=5000)
parser.add_argument("--max-rows", type=int, default=0)
args = parser.parse_args()
dataset_dir = Path(args.dataset_dir).resolve()
image_root = Path(args.image_root).resolve()
json_out = Path(args.json_out).resolve()
tmp_out = json_out.with_suffix(json_out.suffix + ".tmp")
parquet_files = sorted(dataset_dir.rglob("*.parquet"))
if not parquet_files:
raise FileNotFoundError(f"No parquet files found under {dataset_dir}")
image_root.mkdir(parents=True, exist_ok=True)
json_out.parent.mkdir(parents=True, exist_ok=True)
total = 0
started = time.time()
with tmp_out.open("w", encoding="utf-8") as fout:
fout.write("[\n")
first = True
for parquet_path in parquet_files:
part = parquet_path.parent.name
shard = parquet_path.stem
shard_dir = image_root / part / shard
shard_dir.mkdir(parents=True, exist_ok=True)
pf = pq.ParquetFile(parquet_path)
local_idx = 0
for batch in pf.iter_batches(
batch_size=args.batch_size,
columns=["id", "conversations", "image_relpath", "image"],
):
for row in batch.to_pylist():
if args.max_rows and total >= args.max_rows:
break
relpath = row.get("image_relpath") or ""
basename = safe_name(relpath, f"{row.get('id') or total}.png")
image_path = shard_dir / f"{local_idx:06d}_{basename}"
image_obj = row.get("image") or {}
image_bytes = image_obj.get("bytes")
if image_bytes is None:
raise ValueError(f"Missing image bytes in {parquet_path} row {local_idx}")
if not image_path.exists() or image_path.stat().st_size != len(image_bytes):
image_path.write_bytes(image_bytes)
record = {
"id": row.get("id"),
"image": str(image_path),
"conversations": row.get("conversations"),
}
if first:
first = False
else:
fout.write(",\n")
json.dump(record, fout, ensure_ascii=False)
total += 1
local_idx += 1
if total % args.progress_every == 0:
elapsed = max(time.time() - started, 1e-6)
rate = total / elapsed
print(f"materialized_rows={total} rate={rate:.1f}/s elapsed={elapsed:.1f}s", flush=True)
if args.max_rows and total >= args.max_rows:
break
if args.max_rows and total >= args.max_rows:
break
fout.write("\n]\n")
os.replace(tmp_out, json_out)
elapsed = max(time.time() - started, 1e-6)
print(f"done rows={total} json={json_out} images={image_root} elapsed={elapsed:.1f}s", flush=True)
if __name__ == "__main__":
main()