CREPE (full, tiny) — ONNX
CREPE (Kim et al., CREPE: A Convolutional Representation for Pitch Estimation, ICASSP 2018) via torchcrepe 0.0.24, both capacities it ships: full and tiny. A CNN on raw 1024-sample frames.
Exported to ONNX with the model's own front end inside the graph: feed 16 kHz mono audio, get the model's own output — no torch, librosa or reimplemented STFT/mel needed, and nothing that can quietly differ from the original. Every export was checked frame by frame against the original PyTorch pipeline (below), and measured on PTDB-TUG speech against the other exports in this family and against pyin.
| file | model | parameters | size |
|---|---|---|---|
crepe-full.onnx |
CREPE full | 22.2 M | 89.0 MB |
crepe-tiny.onnx |
CREPE tiny | 0.49 M | 2.0 MB |
Same family: rmvpe-onnx · fcpe-onnx · crepe-onnx · pesto-onnx.
Use
# pip install onnxruntime numpy soundfile soxr huggingface_hub
import soundfile as sf, soxr
from huggingface_hub import hf_hub_download
import importlib.util
repo = "Scicom-intl/crepe-onnx"
spec = importlib.util.spec_from_file_location("pitch_onnx", hf_hub_download(repo, "pitch_onnx.py"))
pitch_onnx = importlib.util.module_from_spec(spec); spec.loader.exec_module(pitch_onnx)
model = pitch_onnx.PitchModel(hf_hub_download(repo, "crepe-full.onnx")) # threshold= to override voicing
y, sr = sf.read("speech.wav", dtype="float32", always_2d=True)
y = soxr.resample(y.mean(1), sr, 16000)
f0, voiced, confidence = model(y) # one per 10 ms frame (frame i at i * 10 ms; FCPE + 5 ms); f0 = 0 unvoiced
pitch_onnx.py is numpy + onnxruntime only: it cuts CREPE's frames, decodes the 360-bin salience
the way the models ship (salience-weighted mean of the 9 bins around the peak; CREPE/RMVPE bins are
20 cents from 32.70 Hz, FCPE's are evenly spaced 32.7–1975.5 Hz) and applies the voicing threshold.
Details
CREPE full
- Input:
framesfloat32 [T, 1024] — raw 16 kHz samples, audio zero-padded 512 each side, hop 160 - Output:
saliencefloat32 [T, 360], T = N // 160 + 1 frames, frame i centred at i × 10 ms. - Front end: torchcrepe's per-frame mean/std normalisation is inside the graph; cutting the frames is
pitch_onnx.crepe_frames(batch long clips by frames). - Exactness vs the original PyTorch pipeline: 4 clips (speech of three lengths + 3 s of noise, 2696 frames): max |ONNX − PyTorch| salience 2.98e-07, max pitch difference 0.00002 cents (1 cent = 1/100 semitone), voicing agreement 100.0 %.
- Voicing threshold: 0.61 (chosen on PTDB-TUG's dev speakers, lowest F0 frame error; the upstream default is 0.21).
Accuracy on PTDB-TUG's 16 test speakers (400 utterances per condition), in %:
| condition | RPA ↑ | RCA ↑ | GPE ↓ | VDE ↓ | FFE ↓ | VR ↑ | VFA ↓ |
|---|---|---|---|---|---|---|---|
| clean | 75.15 | 76.68 | 2.68 | 5.89 | 6.43 | 84.63 | 2.93 |
| white noise 10 dB | 74.30 | 75.90 | 2.86 | 5.42 | 5.98 | 83.12 | 1.83 |
| white noise 0 dB | 69.51 | 70.90 | 2.59 | 6.44 | 6.92 | 76.53 | 1.12 |
| pink noise 10 dB | 73.31 | 75.03 | 3.06 | 6.00 | 6.59 | 81.44 | 2.07 |
| pink noise 0 dB | 61.56 | 62.98 | 3.24 | 8.97 | 9.48 | 66.77 | 1.37 |
CPU speed (onnxruntime, x86 server CPU; RTF = compute seconds per second of audio; peak RSS is the whole Python process, librosa and numpy included):
| threads | audio | RTF (compute s / audio s) | peak RSS |
|---|---|---|---|
| 1 | 10 s | 2.0914 | 2473 MB |
| 4 | 10 s | 0.5239 | 2476 MB |
| 1 | 30 s | 2.0671 | 2508 MB |
CREPE tiny
- Input:
framesfloat32 [T, 1024] — as CREPE full - Output:
saliencefloat32 [T, 360], T = N // 160 + 1 frames, frame i centred at i × 10 ms. - Front end: As CREPE full.
- Exactness vs the original PyTorch pipeline: 4 clips (speech of three lengths + 3 s of noise, 2696 frames): max |ONNX − PyTorch| salience 4.47e-07, max pitch difference 0.00004 cents (1 cent = 1/100 semitone), voicing agreement 100.0 %.
- Voicing threshold: 0.58 (chosen on PTDB-TUG's dev speakers, lowest F0 frame error; the upstream default is 0.21).
Accuracy on PTDB-TUG's 16 test speakers (400 utterances per condition), in %:
| condition | RPA ↑ | RCA ↑ | GPE ↓ | VDE ↓ | FFE ↓ | VR ↑ | VFA ↓ |
|---|---|---|---|---|---|---|---|
| clean | 74.75 | 76.23 | 2.40 | 5.86 | 6.33 | 82.73 | 2.29 |
| white noise 10 dB | 73.81 | 75.33 | 2.53 | 5.58 | 6.07 | 81.52 | 1.54 |
| white noise 0 dB | 68.66 | 70.23 | 2.85 | 6.70 | 7.21 | 75.30 | 1.07 |
| pink noise 10 dB | 72.32 | 73.82 | 2.57 | 5.92 | 6.41 | 79.60 | 1.39 |
| pink noise 0 dB | 60.26 | 61.77 | 3.42 | 8.77 | 9.31 | 65.92 | 0.85 |
CPU speed (onnxruntime, x86 server CPU; RTF = compute seconds per second of audio; peak RSS is the whole Python process, librosa and numpy included):
| threads | audio | RTF (compute s / audio s) | peak RSS |
|---|---|---|---|
| 1 | 10 s | 0.0906 | 580 MB |
| 4 | 10 s | 0.0249 | 576 MB |
| 1 | 30 s | 0.0917 | 614 MB |
Comparison on PTDB-TUG (F0 frame error, %, lower is better)
FFE = (voicing-decision errors + gross pitch errors > 20 %) / all frames — the single number that counts both "is this frame voice" and "how wrong is the pitch". Reference: PTDB-TUG's laryngograph-derived f0 (RAPT, 10 ms). Speakers F01 F02 M01 M02 were used ONLY to pick each method's voicing threshold and frame lag (clean audio, lowest FFE); the table is the other 16 speakers, 400 utterances per condition, scored once. Noise is added at the stated SNR over the whole utterance. Best per row in bold.
| condition | RMVPE | FCPE | CREPE full | CREPE tiny | PESTO | pyin (librosa 0.11) |
|---|---|---|---|---|---|---|
| clean | 3.09 | 2.77 | 6.43 | 6.33 | 5.58 | 7.72 |
| white noise 10 dB | 3.18 | 2.95 | 5.98 | 6.07 | 5.99 | 8.32 |
| white noise 0 dB | 3.56 | 3.39 | 6.92 | 7.21 | 7.46 | 16.92 |
| pink noise 10 dB | 3.48 | 3.30 | 6.59 | 6.41 | 6.54 | 8.36 |
| pink noise 0 dB | 4.47 | 4.78 | 9.48 | 9.31 | 8.99 | 17.18 |
Metrics per condition for every method, the chosen thresholds/lags and the CPU timings are in
benchmark.json; the harness is export/evaluate.py.
How it was exported
export/export.py (torch 2.8, legacy ONNX exporter, opset 17). The STFT is two conv1ds with
fixed DFT kernels (torch.stft's complex output doesn't export), equal to torch.stft to float32
rounding. export/decode.py is the decoder the parity check uses.
License and credits
Model and weights: marl/crepe (MIT, Copyright (c) 2018 Jong Wook Kim), PyTorch port maxrmorrison/torchcrepe (MIT, Copyright (c) 2020 Max Morrison). ONNX conversion, evaluation and packaging by Scicom.