Skip to content

Commit c774127

Browse files
authored
Merge pull request #119 from weixlu/serilization
avoid decode/encode overhead in benchmark dataset loading
2 parents 4d3826f + 5a9a349 commit c774127

3 files changed

Lines changed: 44 additions & 57 deletions

File tree

validation/ned_benchmark.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import statistics
4242
import sys
4343
import traceback
44-
from collections.abc import Callable, Iterable, Iterator
44+
from collections.abc import Callable, Iterator
4545
from pathlib import Path
4646

4747
from homr.transformer.vocabulary import EncodedSymbol
@@ -240,7 +240,7 @@ def update_ned_scores(
240240

241241

242242
def run_benchmark(
243-
samples: Iterable[tuple[str, str, Path | None]],
243+
samples: list[tuple[str, str, Path]],
244244
tool: Callable[[str, Path | None], str],
245245
limit: int | None = None,
246246
verbose: bool = False,
@@ -253,7 +253,7 @@ def run_benchmark(
253253
"""
254254
Wire data source, tool, and check together.
255255
256-
samples: iterable of (sample_id, kern_text, image_path) from any data source
256+
samples: list of (sample_id, kern_text, image_path) from any data source
257257
tool: (kern_text, image_path) -> output_text (MusicXML or **kern)
258258
kern_parser: "native" (default) or "music21" - kern ground-truth parser
259259
xml_parser: "native" (default), "music21", "musicdiff", or "musicdiff_detailed"
@@ -280,15 +280,9 @@ def run_benchmark(
280280
results: list[NedResult] = []
281281
failures: list[tuple[str, str]] = []
282282

283-
# Collect from iterator (applying limit and skips) so we can optionally batch.
284-
all_from_iter: list[tuple[str, str, Path | None]] = []
285-
for count, triple in enumerate(samples):
286-
if limit is not None and count >= limit:
287-
break
288-
all_from_iter.append(triple)
289-
290-
skipped = sum(1 for s, _, _ in all_from_iter if s in skip_ids)
291-
active = [(s, k, i) for s, k, i in all_from_iter if s not in skip_ids]
283+
samples = samples[:limit]
284+
active = [s for s in samples if s[0] not in skip_ids]
285+
skipped = len(samples) - len(active)
292286

293287
if xml_parser in ("musicdiff", "musicdiff_detailed"):
294288
_musicdiff_register_once()

validation/polish-scores.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# flake8: noqa: S101
2+
13
"""
24
btrkeks/polish-scores benchmark: measures OMR quality on the Polish Scores dataset.
35
@@ -8,7 +10,6 @@
810

911
import argparse
1012
import tempfile
11-
from collections.abc import Iterator
1213
from pathlib import Path
1314

1415
from validation.ned_benchmark import run_benchmark, update_ned_scores
@@ -28,23 +29,22 @@ def _add_kern_header(kern: str) -> str:
2829
return kern
2930

3031

31-
def iter_polish_scores(
32-
image_dir: Path | None = None,
33-
) -> Iterator[tuple[str, str, Path | None]]:
32+
def get_polish_scores_samples(
33+
image_dir: Path,
34+
) -> list[tuple[str, str, Path]]:
3435
"""Yield (sample_id, kern_text, image_path) for each sample in btrkeks/polish-scores."""
35-
from datasets import load_dataset # type: ignore # noqa: PLC0415
36+
from datasets import Image, load_dataset # type: ignore # noqa: PLC0415
3637

37-
ds = load_dataset("btrkeks/polish-scores")
38-
for i, sample in enumerate(ds["train"]):
38+
ds = load_dataset("btrkeks/polish-scores")["train"]
39+
ds = ds.cast_column("image", Image(decode=False)) # Don't decode on image colume.
40+
result = []
41+
for i, sample in enumerate(ds):
42+
assert sample["transcription_kern"] and sample["image"]["bytes"]
3943
kern = _add_kern_header(sample["transcription_kern"])
40-
image_path: Path | None = None
41-
if image_dir is not None:
42-
img = sample.get("image")
43-
if img is not None and hasattr(img, "save"):
44-
candidate = image_dir / f"{i}.png"
45-
img.save(candidate)
46-
image_path = candidate
47-
yield str(i), kern, image_path
44+
image_path = image_dir / f"{i}.png"
45+
image_path.write_bytes(sample["image"]["bytes"])
46+
result.append((str(i), kern, image_path))
47+
return result
4848

4949

5050
def main() -> None:
@@ -114,7 +114,7 @@ def main() -> None:
114114
tool = TOOLS[args.tool]
115115
with tempfile.TemporaryDirectory() as image_dir:
116116
run_benchmark(
117-
iter_polish_scores(image_dir=Path(image_dir)),
117+
get_polish_scores_samples(Path(image_dir)),
118118
tool,
119119
limit=args.limit,
120120
verbose=args.verbose,

validation/smb.py

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# flake8: noqa: S101
2+
13
"""
24
PRAIG/SMB benchmark: measures OMR quality on the SMB dataset.
35
@@ -12,50 +14,41 @@
1214

1315
import argparse
1416
import tempfile
15-
from collections.abc import Iterator
1617
from pathlib import Path
1718

1819
from validation.ned_benchmark import run_benchmark, update_ned_scores
1920
from validation.tools import TOOLS
2021

2122

22-
def iter_smb(split: str, image_dir: Path | None = None) -> Iterator[tuple[str, str, Path | None]]:
23+
def get_smb_samples(image_dir: Path) -> list[tuple[str, str, Path]]:
2324
"""Yield (sample_id, kern_text, image_path) for each page in PRAIG/SMB.
2425
2526
Passes the full page image to allow proper end-to-end OMR evaluation.
2627
Ground truth priority: page.kern > top-level kern > concatenated region kern.
2728
image_path is only set when image_dir is provided and the page has an image.
2829
"""
29-
from datasets import load_dataset # type: ignore # noqa: PLC0415
30-
31-
ds = load_dataset("PRAIG/SMB")
32-
for i, sample in enumerate(ds[split]):
33-
kern = ""
34-
page = sample.get("page", {})
35-
if isinstance(page, dict):
36-
kern = page.get("kern") or ""
37-
if not kern:
38-
kern = sample.get("kern") or ""
39-
if not kern:
40-
parts = [r.get("kern", "") for r in sample.get("regions", []) if r.get("kern")]
41-
kern = "\n".join(parts)
42-
if not kern:
43-
continue
44-
45-
image_path: Path | None = None
46-
if image_dir is not None:
47-
img = sample.get("image")
48-
if img is not None and hasattr(img, "save"):
49-
candidate = image_dir / f"{i}.png"
50-
img.save(candidate)
51-
image_path = candidate
52-
53-
yield str(i), kern, image_path
30+
from datasets import Image, load_dataset # type: ignore # noqa: PLC0415
31+
32+
ds = load_dataset("PRAIG/SMB")["test"]
33+
ds = ds.cast_column("image", Image(decode=False)) # Don't decode on image colume.
34+
result = []
35+
for i, sample in enumerate(ds):
36+
assert "kern" not in sample and isinstance(
37+
sample["regions"], list
38+
) # not a global `kern` field, but a list of regions.
39+
assert sample["image"]["bytes"]
40+
41+
parts = [r["kern"] for r in sample["regions"] if r["kern"]]
42+
kern = "\n".join(parts)
43+
image_path = image_dir / f"{i}.png"
44+
image_path.write_bytes(sample["image"]["bytes"])
45+
46+
result.append((str(i), kern, image_path))
47+
return result
5448

5549

5650
def main() -> None:
5751
parser = argparse.ArgumentParser(description="OMR-NED benchmark for PRAIG/SMB.")
58-
parser.add_argument("--split", type=str, default="test", help="Dataset split (default: test).")
5952
parser.add_argument("--limit", type=int, default=None, help="Only process N samples.")
6053
parser.add_argument("--verbose", action="store_true", help="Print traceback on failure.")
6154
parser.add_argument("--output", type=str, default=None, help="Path to SQLite output file.")
@@ -121,7 +114,7 @@ def main() -> None:
121114
tool = TOOLS[args.tool]
122115
with tempfile.TemporaryDirectory() as image_dir:
123116
run_benchmark(
124-
iter_smb(args.split, image_dir=Path(image_dir)),
117+
get_smb_samples(image_dir=Path(image_dir)),
125118
tool,
126119
limit=args.limit,
127120
verbose=args.verbose,

0 commit comments

Comments
 (0)