Saltar al contenido
ModelPublicadoExterno
Descargar

Transcoda 59M Zeroshot v1

End-to-end zero-shot Optical Music Recognition. A compact 59M-parameter vision-encoder-decoder that turns raw score images directly into kern (Humdrum) symbolic transcriptions. Trained from scratch on synthetic data...

TipoOtherModelo basefacebook/convnextv2-tiny-22k-224VersiónRevision b529f8aBcalidad

Fuente del modelo

Tipo
Other
Tamaño del archivo
112–224 MB
Modelo base
facebook/convnextv2-tiny-22k-224
Versión
vRevision b529f8a
Actualizado
14 sept 2026
Descargas
378
Fuente
Hugging Face

Descripción de la fuente

Transcoda 59M Zero-Shot v1

End-to-end zero-shot Optical Music Recognition. A compact 59M-parameter vision-encoder-decoder that turns raw score images directly into **kern (Humdrum) symbolic transcriptions. Trained from scratch on synthetic data only.

Paired benchmarks: btrkeks/verovio-synth-omr (synthetic) and btrkeks/polish-scores (real historical scans).

Quick load (transformers)

from transformers import AutoModelForCausalLM, PreTrainedTokenizerFast

model = AutoModelForCausalLM.from_pretrained(
    "btrkeks/transcoda-59M-zeroshot-v1",
    trust_remote_code=True,
)
tokenizer = PreTrainedTokenizerFast.from_pretrained("btrkeks/transcoda-59M-zeroshot-v1")

trust_remote_code=True is required because the model uses a custom vision-encoder-decoder architecture not yet in the transformers registry. On first load the ConvNeXt-V2-Tiny base weights are re-downloaded from facebook/convnextv2-tiny-22k-224 and then overwritten by the Transcoda checkpoint; this is expected.

Preprocessing

The model expects a single page image normalized to 1485 × 1050 pixels (height × width) with float32 pixel values in [-1, 1]:

  1. Convert to RGB.
  2. Resize to width 1050 preserving aspect ratio (bilinear).
  3. If the resized height exceeds 1485, top-crop; otherwise white-pad at the bottom to reach exactly 1485.
  4. Normalize to [-1, 1] (subtract 0.5, divide by 0.5 per channel).
  5. Pass as pixel_values of shape (1, 3, 1485, 1050) plus an image_sizes tensor [[1485, 1050]] to model.generate(...).

The canonical implementation is preprocess_pil_image in src/data/preprocessing.py in the project repository.

Full inference snippet

import torch
from PIL import Image
import numpy as np
from transformers import AutoModelForCausalLM, PreTrainedTokenizerFast

REPO = "btrkeks/transcoda-59M-zeroshot-v1"
device = "cuda" if torch.cuda.is_available() else "cpu"
model = AutoModelForCausalLM.from_pretrained(REPO, trust_remote_code=True).to(device).eval()
tokenizer = PreTrainedTokenizerFast.from_pretrained(REPO)

def preprocess(path, target_w=1050, target_h=1485):
    img = Image.open(path).convert("RGB")
    new_h = max(1, int(img.height * (target_w / img.width)))
    img = img.resize((target_w, new_h), Image.BILINEAR)
    arr = np.array(img)
    if arr.shape[0] > target_h:
        arr = arr[:target_h]
    elif arr.shape[0] < target_h:
        pad = np.full((target_h - arr.shape[0], target_w, 3), 255, dtype=arr.dtype)
        arr = np.concatenate([arr, pad], axis=0)
    t = torch.from_numpy(arr).permute(2, 0, 1).float() / 255.0
    t = (t - 0.5) / 0.5
    return t.unsqueeze(0)

pixel_values = preprocess("page.png").to(device)
image_sizes = torch.tensor([[1485, 1050]], device=device)

with torch.no_grad():
    out = model.generate(
        pixel_values=pixel_values,
        image_sizes=image_sizes,
        max_length=2048,
        do_sample=False,
        num_beams=1,
        repetition_penalty=1.1,
    )

print(tokenizer.decode(out[0], skip_special_tokens=True))

For grammar-constrained decoding (guarantees formally valid **kern) and beam search, use the project repository's scripts/inference.py.

Loading the raw .ckpt (paper reproducibility)

The original Lightning checkpoint is also distributed in this repo as transcoda-59M-zeroshot-v1.ckpt. Load it from a clone of the Transcoda repository:

import torch
from src.model.checkpoint_loader import load_model_from_checkpoint

loaded = load_model_from_checkpoint("transcoda-59M-zeroshot-v1.ckpt", torch.device("cpu"))
model = loaded.model

This matches the inference path used for the paper's reported metrics.

Architecture

ComponentSpec
EncoderConvNeXt-V2-Tiny, pretrained on ImageNet-22k
Patch grid47 × 33 (from a 1485 × 1050 input)
Projector2-layer MLP, encoder dim 768 → decoder dim 512
Positional encoding2D sinusoidal on the encoder grid, RoPE on the decoder
Decoder8-layer Transformer, d_model=512, dim_ff=1024, 8 heads
Vocab3,000-token BPE (**kern source)
Max seq len2,048
Parameters58.8 M total

Training data

310,554 synthetic page images rendered with Verovio, sourced from PDMX, Musetrainer, Grandstaff, OpenScore Lieder, and OpenScore String Quartets. Targets are canonicalized via a deterministic **kern normalization pipeline so each score maps to a single canonical sequence. Augmentation adds expressive marks (dynamics, pedals, tempo, etc.) to the rendered image without changing the target — this asymmetry teaches the decoder to ignore notation that is not part of **kern.

No real-scan or Polish data is used for training or model selection.

Benchmarks

OMR-NED on the released benchmarks (lower is better):

ModelParamsVerovio synth ↓Polish (real) ↓
SMT++11M92.23%80.16%
Legato943M43.91%86.73%
Transcoda 59M (beam)59M18.46%63.97%

Headline numbers use beam search with width 3, repetition_penalty=1.1, max_length=2048. See scripts/benchmark/README.md in the project repository for reproduction commands and ablations.

Decoding

Three configurations are documented in the paper:

  • Greedy (default in this card's generation_config.json): do_sample=false, num_beams=1, repetition_penalty=1.1, max_length=2048.
  • Beam search (best CER, headline metric): num_beams=3, length_penalty=1.0, otherwise as above.
  • Grammar-constrained: applies a **kern grammar (grammars/kern.gbnf) via custom logits processors. Guarantees structural validity; requires the project repository.

The repetition penalty is preferred over no_repeat_ngram_size — music is intrinsically repetitive at every scale, and banning n-grams breaks legitimate output. See the project CLAUDE.md for details.

Limitations

  • Trained exclusively on synthetic Verovio renders. Domain gap on real scans is significant: 18.46% OMR-NED on clean Verovio pages vs 63.97% on Polish historical scans.
  • No fine-tuning on Polish or any other real-world corpus.
  • Single layout engine in training data; other engravers may degrade.
  • Fixed input geometry (1485 × 1050). Multi-page or unusual aspect ratios must be split or letterboxed by the caller.

License

CC BY 4.0.

Citation

@misc{dratschuk2026transcodaendtoendzeroshotoptical,
      title={Transcoda: End-to-End Zero-Shot Optical Music Recognition via Data-Centric Synthetic Training},
      author={Daniel Dratschuk and Paul Swoboda},
      year={2026},
      eprint={2605.10835},
      archivePrefix={arXiv},
      primaryClass={cs.CV},
      url={https://arxiv.org/abs/2605.10835},
}

Fuentes

1 fuente
Hugging FacePrincipalVersión b529f8aa5d996d9224df3395b5b92d0867343c91
huggingface.co/btrkeks/transcoda-59M-zeroshot-v1/tree/b529f8aa5d996d9224df3395b5b92d0867343c91

Verificado 20 ago

Artefactos del modelo

2 artefactos

model.safetensors

safetensors · 224 MB · SHA-256 c173a3b75b8a…e52a · Hugging Face

Descargar

transcoda-59M-zeroshot-v1.ckpt

ckpt · 112 MB · SHA-256 3ce7387b9477…dafc · Hugging Face

Descargar

Extractos de fuentes

2 extractos

--- license: cc-by-4.0 library_name: transformers pipeline_tag: image-to-text base_model: facebook/convnextv2-tiny-22k-224 tags: - omr - optical-music-recognition - kern - humdrum - music - vision-encoder-decoder - convnextv2 datasets: - btrkeks/verovio-synth-omr - btrkeks/polish-scores model-index: - name: transcoda-59M-zeroshot-v1 results: - task: type: image-to-text name: Optical Music Recognition dataset: type: btrkeks/verovio-synth-omr name: Verovio Synthetic OMR Benchmark metrics: - type: OMR-NED value: 18.46 name: OMR-NED (lower is better) - task: type: image-to-text name: Optical Music Recognition dataset: type: btrkeks/polish-scores name: Polish Historical-Scan OMR Benchmark metrics: - type: OMR-NED value: 63.97 name: OMR-NED (lower is better) --- # Transcoda 59M Zero-Shot v1 End-to-end zero-shot Optical Music Recognition. A compact 59M-parameter vision-encoder-decoder that turns raw score images directly into [`**kern`](https://www.humdrum.org/rep/kern/) (Humdrum) symbolic transcriptions. Trained from scratch on synthetic data only. Paired benchmarks: [`btrkeks/verovio-synth-omr`](https://huggingface.co/datasets/btrkeks/verovio-synth-omr) (synthetic) and [`btrkeks/polish-scores`](https://huggingface.co/datasets/btrkeks/polish-scores) (real historical scans). ## Quick load (transformers) ```python from transformers import AutoModelForCausalLM, PreTrainedTokenizerFast model = AutoModelForCausalLM.from_pretrained( "btrkeks/transcoda-59M-zeroshot-v1", trust_remote_code=True, ) tokenizer = PreTrainedTokenizerFast.from_pretrained("btrkeks/transcoda-59M-zeroshot-v1") ``` `trust_remote_code=True` is required because the model uses a custom vision-encoder-decoder architecture not yet in the `transformers` registry. On first load the ConvNeXt-V2-Tiny base weights are re-downloaded from [`facebook/convnextv2-tiny-22k-224`](https://huggingface.co/facebook/convnextv2-tiny-22k-224) and then overwritten by the Transcoda checkpoint; this is expected. ## Preprocessing The model expects a single page image normalized to **1485 × 1050 pixels** (height × width) with float32 pixel values in `[-1, 1]`: 1. Convert to RGB. 2. Resize to width 1050 preserving aspect ratio (bilinear). 3. If the resized height exceeds 1485, top-crop; otherwise white-pad at the bottom to reach exactly 1485. 4. Normalize to `[-1, 1]` (subtract 0.5,...

Source context: 378 downloads · 0 likes · Pipeline image-to-text · Library transformers · Repo btrkeks/transcoda-59M-zeroshot-v1