buddy-pronunciation-onnx

int8 ONNX exports of two phoneme-recognition models, for on-device pronunciation assessment in Buddy.

These are format conversions only β€” no retraining, no fine-tuning. See NOTICE for the exact export and quantization steps, as Apache-2.0 requires.

Contents

Path Language Size Vocabulary
en/v1/model.int8.onnx English 357 MB 125 ARPAbet tokens, with stress digits
zh/v1/model.int8.onnx Mandarin 358 MB 392 IPA tokens, with tone markers

Each sits beside its vocab.json, copied verbatim from the source repository.

Paths are versioned and immutable. A future export goes to v2/; files already published are never replaced, so a client that downloaded v1 keeps exactly what it verified.

Why two models

They were chosen by measurement, not by reputation. Both were run against the same clips β€” clean speech, a planted /v/β†’/w/ substitution, and accented speech β€” and scored against CMUdict:

Phone error rate Notes
en/v1 0.0% Emits ARPAbet, so it lines up with CMUdict without a translation table
zh/v1 4.3% The only one of the candidates with Mandarin tone tokens

The English model was preferred over an L2-trained alternative that scored worse, and over a smaller 123 MB model that carries no stress information.

The Mandarin model mis-hears English think as s Ιͺ Ε‹ k β€” exactly the substitution a learner makes β€” so it is not used for English, where a false accusation would be worse than a missed error.

Usage

Both are CTC models. Feed 16 kHz mono float32 audio, normalized to zero mean and unit variance (what wav2vec2 was trained on β€” skipping this does not error, it quietly degrades every output):

import numpy as np, soundfile as sf, onnxruntime as ort, json

audio, sr = sf.read("speech.wav")          # 16 kHz mono
audio = audio.astype(np.float32)
audio = (audio - audio.mean()) / (audio.std() + 1e-7)

sess = ort.InferenceSession("en/v1/model.int8.onnx")
logits = sess.run(None, {"input_values": audio[None, :]})[0]   # [1, frames, vocab]

vocab = {v: k for k, v in json.load(open("en/v1/vocab.json")).items()}
ids = logits.argmax(-1)[0]
out, prev = [], None
for i in ids:                               # collapse CTC repeats and blanks
    if i != prev and i != 0:
        out.append(vocab[int(i)])
    prev = i
print(" ".join(out))

The output is logits, not probabilities β€” apply log-softmax per frame before using them as posteriors.

Measured at ~77 ms for a 2.3 s clip on CPU, roughly 30Γ— faster than real time.

Licence

Apache-2.0, inherited from both originals. Cite the original authors rather than this repository; it exists only to host a runnable format.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for asingingbird/buddy-pronunciation-onnx

Quantized
(2)
this model