davanstrien's picture
download
raw
5.5 kB
"""
Job 1 (GPU): run PaddleOCR-VL-1.6 over the olmOCR-bench `old_scans` subset and
write candidate markdown in the exact layout `olmocr.bench.benchmark` expects.
Runs with PaddlePaddle's docker image (paddle 3.2.1 + paddleocr 3.6.0 + the v1.6
weights preinstalled) via the image's python3.10 -- not uv. Every import here
(paddleocr, huggingface_hub, stdlib) is already in the image, so there is no
PEP 723 header.
Fidelity: the markdown extraction matches olmOCR-bench's own runner
(`olmocr/bench/runners/run_paddlevl.py`) -- `res.markdown["markdown_texts"]`, per
page, with a bare default pipeline and NO tuning (no max_pixels / prompts / dpi).
The one intentional difference is `pipeline_version="v1.6"`: upstream calls
`PaddleOCRVL()` with no version (an earlier PaddleOCR-VL), while this measures 1.6
as its model card specifies. So we follow the bench runner's extraction and
PaddlePaddle's documented v1.6 defaults.
This image runs as the non-root `paddleocr` user, which CANNOT write the bucket
FUSE mount (root-owned). So we write outputs to a container-local dir and push
them with `sync_bucket()` (mount-free HTTP upload) at the end. The bucket is
mounted read-only purely to deliver this script.
Delivery + run (see README for full commands):
hf buckets cp convert.py hf://buckets/davanstrien/paddleocr-vl16-oldscans/convert.py
hf jobs run --flavor l4x1 -s HF_TOKEN \
-v hf://buckets/davanstrien/paddleocr-vl16-oldscans:/bucket:ro \
ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleocr-vl:latest-nvidia-gpu \
python3 /bucket/convert.py
Env:
OUT_ROOT local staging dir (default /tmp/olmocr-oldscans-out)
BUCKET bucket to sync results to (default below)
PIPELINE_VERSION PaddleOCRVL version (default v1.6). "v1" = the original 0.9B
PaddleOCR-VL = the version on the olmOCR-bench leaderboard
(37.8) -> run it (with a distinct CANDIDATE) for a strict
same-version reproduction.
CANDIDATE output subfolder + model label (default paddleocr_vl_16)
LIMIT cap number of PDFs (plumbing smoke test; 0 = all). With a cap,
the un-converted docs are scored FAILED, so the result is not
a representative score -- use a smoke run only to check plumbing.
"""
import json
import os
from collections import defaultdict
from pathlib import Path
from huggingface_hub import hf_hub_download, sync_bucket
from paddleocr import PaddleOCRVL
BENCH_REPO = "allenai/olmOCR-bench"
JSONL_PATH = "bench_data/old_scans.jsonl"
CANDIDATE = os.environ.get("CANDIDATE", "paddleocr_vl_16") # any name except "pdfs"
PIPELINE_VERSION = os.environ.get("PIPELINE_VERSION", "v1.6")
OUT_ROOT = Path(os.environ.get("OUT_ROOT", "/tmp/olmocr-oldscans-out"))
BUCKET = os.environ.get("BUCKET", "hf://buckets/davanstrien/paddleocr-vl16-oldscans")
LIMIT = int(os.environ.get("LIMIT", "0"))
# ---- test manifest ----------------------------------------------------------
jsonl_local = hf_hub_download(BENCH_REPO, JSONL_PATH, repo_type="dataset")
tests = [json.loads(ln) for ln in Path(jsonl_local).read_text().splitlines() if ln.strip()]
pages_by_pdf = defaultdict(set)
for t in tests:
pages_by_pdf[t["pdf"]].add(int(t.get("page", 1)))
print(f"{len(tests)} tests across {len(pages_by_pdf)} PDFs -> {OUT_ROOT}", flush=True)
# ---- model (vendor default, no tuning) --------------------------------------
print(f"pipeline_version={PIPELINE_VERSION} candidate={CANDIDATE}", flush=True)
pipeline = PaddleOCRVL(pipeline_version=PIPELINE_VERSION)
def resolve_pdf(pdf_field):
"""The jsonl `pdf` field may or may not carry a pdfs/ prefix; try variants."""
for cand in (f"bench_data/{pdf_field}", f"bench_data/pdfs/{pdf_field}", pdf_field):
try:
return hf_hub_download(BENCH_REPO, cand, repo_type="dataset")
except Exception:
continue
raise FileNotFoundError(pdf_field)
def page_markdowns(pdf_path):
"""Per-page markdown, exactly as run_paddlevl.py does: res.markdown['markdown_texts']."""
return [res.markdown["markdown_texts"] for res in pipeline.predict(str(pdf_path))]
# ---- convert ----------------------------------------------------------------
cand_dir = OUT_ROOT / CANDIDATE
items = sorted(pages_by_pdf.items())
if LIMIT:
items = items[:LIMIT]
print(f"LIMIT={LIMIT} (plumbing smoke test -- expect a low score)", flush=True)
for i, (pdf_field, pages) in enumerate(items, 1):
try:
mds = page_markdowns(resolve_pdf(pdf_field))
except Exception as e: # keep going; a missing page just fails its tests
print(f"[WARN] {pdf_field}: {e}", flush=True)
mds = []
md_base = os.path.splitext(pdf_field)[0] # mirrors benchmark.py exactly
for pg in pages:
md = mds[pg - 1] if 0 <= pg - 1 < len(mds) else "" # 1-indexed page -> 0-indexed
fp = cand_dir / f"{md_base}_pg{pg}_repeat1.md"
fp.parent.mkdir(parents=True, exist_ok=True)
fp.write_text(md)
n = len(mds[0]) if mds else 0
print(f"[{i}/{len(items)}] {pdf_field} -> {n} chars", flush=True)
# the scorer needs the jsonl next to the candidate folder
(OUT_ROOT / "old_scans.jsonl").write_text(Path(jsonl_local).read_text())
# push results to the bucket over HTTP (the FUSE mount is not writable as non-root)
print(f"Syncing {OUT_ROOT} -> {BUCKET}", flush=True)
sync_bucket(str(OUT_ROOT), BUCKET)
print("Done.", flush=True)

Xet Storage Details

Size:
5.5 kB
·
Xet hash:
724800e76ca3611f4aa8234031bb9179e12372f6677e4b0d8ad2a01a54710751

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