Pruned Stateless Zipformer RNN-T Streaming Robust ES v1

zipformer-streaming-robust-es-v1 is Bookbot's causal Spanish pruned-stateless Zipformer RNN-T phoneme recognizer. It emits atomic, whitespace-interpretable IPA phone tokens rather than words. The canonical inference state is the exact cumulative averaged-model difference over epochs 76–80; its 639 tensors were checked against the production Icefall averaging path before the source checkpoints were pruned.

License and permitted use

The model weights are published under CC BY-NC-SA 3.0 because training included the TinyVox Spanish subset, which is derived from TalkBank/PhonBank data under that license and is restricted to non-commercial use. Do not use these weights in a commercial product or service. Follow the TalkBank Ground Rules, retain attribution, and share adaptations under compatible terms.

The included Icefall inference script retains its upstream Apache-2.0 source-code license. Common Voice and SLR72 retain their own source licenses. TinyVox audio, metadata, and utterance-level recognition output are not included in this repository or the companion public datasets.

Training data

Versioned public training datasets with the exact v1 schema are:

Each row contains only id, audio, and the exact canonical ipa_transcript consumed by this model.

Output inventory

data/lang_phone/tokens.txt is the authoritative symbol table. It contains 28 non-disambiguation entries, including <eps> and <UNK>, plus #0 for graph disambiguation. Phones are atomic tokens; the composite affricate t͡ʃ is one token. The vocabulary differs from v0's older BabyGruut-era inventory and is not numerically compatible with v0 checkpoints.

Streaming configuration

  • Architecture: pruned stateless Zipformer RNN-T
  • Causal streaming: yes
  • Chunk size: 16 encoder frames
  • Left context: 128 frames
  • Encoder layers: 2,2,2,2,2,2
  • Feed-forward dimensions: 512,768,768,768,768,768
  • Encoder dimensions: 192,256,256,256,256,256
  • Encoder unmasked dimensions: 192,192,192,192,192,192
  • Decoder and joiner dimensions: 512
  • Training hardware: 2 NVIDIA RTX 4090 GPUs

Published artifacts

  • epoch-80.pt: full resumable final training state.
  • evaluated-avg-76-80.pt: canonical inference checkpoint used for every reported result.
  • jit_script_chunk_16_left_128.pt: TorchScript export from that exact canonical checkpoint.
  • data/lang_phone/: token, lexicon, and graph artifacts.
  • jit_pretrained_streaming.py: streaming greedy inference example.
  • test_waves/common_voice_es_19696062.wav: CC0 Common Voice 23.0 Spanish sample, resampled to 16 kHz.
  • streaming/evaluation-common-voice-23-0-es-slr72.json: machine-readable corpus provenance and results.
  • model-config.json and SHA256SUMS: reproducibility metadata.
  • tensorboard/ and log/: training metrics and logs.

The sherpa-onnx ORT conversion is published separately at bookbot/sherpa-onnx-ort-zipformer-streaming-robust-es-v1.

Setup and usage

Install Icefall and its dependencies following the Icefall installation guide. Bookbot uses its Icefall fork:

git clone https://github.com/bookbot-hive/icefall
cd icefall/egs/bookbot_es/ASR

Download and run the pre-trained model

Clone this repository and run the included sample:

git lfs install
mkdir -p tmp
git clone \
  https://huggingface.co/bookbot/zipformer-streaming-robust-es-v1 \
  tmp/zipformer-streaming-robust-es-v1

python tmp/zipformer-streaming-robust-es-v1/jit_pretrained_streaming.py \
  --nn-model-filename tmp/zipformer-streaming-robust-es-v1/jit_script_chunk_16_left_128.pt \
  --tokens tmp/zipformer-streaming-robust-es-v1/data/lang_phone/tokens.txt \
  tmp/zipformer-streaming-robust-es-v1/test_waves/common_voice_es_19696062.wav

Observed greedy output for the included sample:

xeneɾalmentelosimmigɾantessesitwaɾonenlapeɾifeɾjadelassjudades

The underlying token sequence exactly matches the production checkpoint's stored greedy hypothesis:

x e n e ɾ a l m e n t e l o s i m m i g ɾ a n t e s s e s i t w a ɾ o n e n l a p e ɾ i f e ɾ j a d e l a s s j u d a d e s

Input audio must be mono 16 kHz WAV or another format supported by torchaudio with a 16 kHz sample rate.

Evaluation

All values are phoneme error rate (PER). Icefall's generic error writer and historical wer-summary-* filenames use the label WER, but the aligned units are whitespace-separated IPA phones.

Evaluation uses the exact epochs 76–80 averaged model, causal chunk size 16, left context 128, and 1,000 decode streams.

Decoder Common Voice 23.0 ES test SLR72 test TinyVox validation TinyVox test
Greedy 2.8076% 1.5325% 25.5180% 33.7509%
Modified beam, 4 active paths 2.6908% 1.3961% 24.5529% 32.9158%
Fast beam, beam 8 / 4 contexts / 32 states / blank penalty 3.1 3.1927% 1.5544% 36.8720% 45.7883%
Reference fast beam, beam 4 / 4 contexts / 32 states / blank penalty 0 74.9781% 50.2461% 85.2399% 88.0634%

Use modified beam search with num_active_paths=4 for this model. The reference fast-beam configuration collapses through excessive blank/deletion bias. A blank penalty selected only on TinyVox validation rescues that collapse but remains worse than modified beam on every reported corpus.

Evaluation limits

The recipe reuses the Common Voice and SLR72 official test splits for validation, so those two results are validation-overlapped rather than independent holdouts. TinyVox test is the independently held-out result; it was evaluated after the fast-beam setting had been selected on TinyVox validation. Common Voice dominates any combined aggregate, so per-corpus values are preferred.

Checkpoint provenance

  • Best recorded validation loss: 0.1675387544560873 at epoch 75.
  • Training completed the configured 80 epochs; this completed run did not early-stop.
  • Canonical averaged inference range: epochs 76–80.
  • epoch-80.pt SHA-256: e6704a4c639f94e7361fb07d6fac698d3ea0c67d8f3eecef4ad6c0423013b646.
  • evaluated-avg-76-80.pt SHA-256: d5cde97d82c214da39c3d9decffa84eaf6b15869c7b6521d2f184a2e59ad30e5.

See SHA256SUMS for every packaged binary and model-config.json for exact export settings.

Training procedure

The historical run used Python 3.12, PyTorch 2.4.0+cu124, k2 1.24.4, Lhotse 1.31.1, and two NVIDIA RTX 4090 GPUs. The retained checkpoint records the clean Icefall branch feature/spanish-phonemization-retrain at 4b746f3b. That recipe revision is the authority for the historical run; the current launcher may contain later checkpoint-retention and early-stopping policy that did not produce these weights.

Install Icefall

git clone https://github.com/bookbot-hive/icefall
cd icefall
export PYTHONPATH="$PWD:${PYTHONPATH:-}"
cd egs/bookbot_es/ASR

Install Icefall and its k2/Lhotse dependencies using the official installation guide. The exact 4b746f3b recipe revision must be available in your checkout for historical data preparation. At publication time that feature revision was recorded by the checkpoint but was not reachable from the public fork, so this is an explicit source-reproducibility limit rather than a claim that current master is identical.

Prepare data

The two public companion datasets expose the accepted Common Voice and SLR72 rows, but exact training additionally requires:

  • pinned full-source snapshots obtained from Mozilla Data Collective and OpenSLR72, identified by historical preparation revisions 591a99e9c5c9e308231746c7baa03eadfe670483 and e7c9924b964eecbdcba1181add860367d3c7ca3a, respectively;
  • an existing verified Common Voice/SLR72 Lhotse fbank store;
  • locally obtained TinyVox Spanish data and the licensed alignment lexicon.

Bookbot no longer hosts those full historical source snapshots. Exact preparation therefore requires preserved local copies matching the recorded revision and manifest hashes. The versioned IPA datasets above contain only accepted final cuts and cannot replace the larger full-source inputs in this historical preparation command.

TinyVox is not redistributed here. Obtain it from TalkBank and comply with CC BY-NC-SA 3.0 and the TalkBank Ground Rules. With those prerequisites, the historical preparation stages are:

python local/prepare_spanish_retrain.py \
  --existing-fbank-dir /path/to/existing/fbank \
  --output-data-dir data \
  --common-voice-source /path/to/common_voice_23_0_es \
  --slr72-source /path/to/slr72_dataset \
  --tinyvox-root /path/to/tinyvox_spanish \
  --tinyvox-alignment-lexicon local/tinyvox_alignment_lexicon.tsv

python local/compute_fbank_tinyvox.py

python local/prepare_lexicon.py \
  --tokens-file es-tokens.txt \
  --lang-dir data/lang_phone

python local/prepare_lang.py \
  --tokens-file es-tokens.txt \
  --lang-dir data/lang_phone

python local/validate_spanish_retrain.py \
  --fbank-dir data/fbank \
  --reports-dir data/reports \
  --tokens-file es-tokens.txt \
  --lang-tokens data/lang_phone/tokens.txt

Preparation is fail-closed: pinned source revisions and manifests, full audio joins, the fixed phone inventory, and TinyVox split isolation must validate before training starts.

Train

This is the effective historical command recorded by epoch-80.pt. The checkpoint confirms keep_last_k=30, seed 42, causal training chunk choices 16,32,64,-1, left-context choices 64,128,256,-1, MUSAN mixing, and SpecAugment. No early stopping was active in the run that produced v1.

export CUDA_VISIBLE_DEVICES="0,1"
export OMP_NUM_THREADS=1

python zipformer/train.py \
  --world-size 2 \
  --num-epochs 80 \
  --start-epoch 1 \
  --exp-dir zipformer/exp-spanish-atomic-phones \
  --manifest-dir data/fbank \
  --lang-dir data/lang_phone \
  --causal 1 \
  --chunk-size "16,32,64,-1" \
  --left-context-frames "64,128,256,-1" \
  --num-encoder-layers 2,2,2,2,2,2 \
  --feedforward-dim 512,768,768,768,768,768 \
  --encoder-dim 192,256,256,256,256,256 \
  --encoder-unmasked-dim 192,192,192,192,192,192 \
  --max-duration 1000 \
  --base-lr 0.04 \
  --keep-last-k 30 \
  --seed 42 \
  --enable-musan true \
  --enable-spec-aug true \
  --use-transducer true \
  --use-fp16 1

The run completed epoch 80. evaluated-avg-76-80.pt is the materialized Icefall cumulative averaged-model difference for epochs 76–80, not a renamed single-epoch checkpoint.

Exporting to ONNX

The streaming exporter emits FP32 and dynamic-INT8 encoder, decoder, and joiner ONNX files. Starting in icefall/egs/bookbot_es/ASR, expose the exact materialized average through a scratch numeric checkpoint name:

native=tmp/zipformer-streaming-robust-es-v1
scratch="$(mktemp -d)"
ln -s "$(realpath "$native/evaluated-avg-76-80.pt")" \
  "$scratch/epoch-999.pt"

python zipformer/export-onnx-streaming.py \
  --tokens "$native/data/lang_phone/tokens.txt" \
  --epoch 999 \
  --avg 1 \
  --use-averaged-model false \
  --exp-dir "$scratch" \
  --num-encoder-layers 2,2,2,2,2,2 \
  --downsampling-factor 1,2,4,8,4,2 \
  --feedforward-dim 512,768,768,768,768,768 \
  --num-heads 4,4,4,8,4,4 \
  --encoder-dim 192,256,256,256,256,256 \
  --query-head-dim 32 \
  --value-head-dim 12 \
  --pos-head-dim 4 \
  --pos-dim 48 \
  --encoder-unmasked-dim 192,192,192,192,192,192 \
  --cnn-module-kernel 31,31,15,15,15,31 \
  --decoder-dim 512 \
  --joiner-dim 512 \
  --context-size 2 \
  --causal true \
  --chunk-size 16 \
  --left-context-frames 128 \
  --use-transducer true

for component in encoder decoder joiner; do
  mv "$scratch/${component}-epoch-999-avg-1-chunk-16-left-128.onnx" \
    "$scratch/${component}-evaluated-avg-76-80-chunk-16-left-128.onnx"
  mv "$scratch/${component}-epoch-999-avg-1-chunk-16-left-128.int8.onnx" \
    "$scratch/${component}-evaluated-avg-76-80-chunk-16-left-128.int8.onnx"
done

The exporter uses ONNX opset 13 and onnxruntime.quantization.quantize_dynamic with QInt8 weights. It quantizes encoder MatMul, decoder MatMul/Gather, and joiner MatMul operations.

Converting ONNX to ORT

The published package used ONNX Runtime 1.23.2 with fixed optimization:

(
  cd "$scratch"
  python -m onnxruntime.tools.convert_onnx_models_to_ort \
    --optimization_style=Fixed \
    .
)

This produces six .ort files plus required_operators.config. Verify the ORT files before publication, then remove the intermediate ONNX files and the scratch checkpoint alias:

python -c 'import glob, sys, onnxruntime as ort; [ort.InferenceSession(p, providers=["CPUExecutionProvider"]) for p in glob.glob(sys.argv[1] + "/*.ort")]' "$scratch"
rm -f "$scratch"/*.onnx "$scratch"/epoch-999.pt

The final, validated ORT artifacts are published in bookbot/sherpa-onnx-ort-zipformer-streaming-robust-es-v1. export-config.json in that repository records the architecture, quantization operators, conversion settings, and output names.

Exporting the TorchScript model

The materialized average can be exposed to Icefall's numeric checkpoint loader through a temporary alias:

ln -s "$PWD/evaluated-avg-76-80.pt" /tmp/bookbot-v1-export/epoch-999.pt

python zipformer/export.py \
  --tokens data/lang_phone/tokens.txt \
  --use-averaged-model false \
  --epoch 999 --avg 1 \
  --exp-dir /tmp/bookbot-v1-export \
  --jit true --causal true \
  --chunk-size 16 --left-context-frames 128 \
  --num-encoder-layers 2,2,2,2,2,2 \
  --feedforward-dim 512,768,768,768,768,768 \
  --encoder-dim 192,256,256,256,256,256 \
  --encoder-unmasked-dim 192,192,192,192,192,192 \
  --use-transducer true

Remove the temporary alias after export. It is not a third retained checkpoint.

Frameworks

Citations

For Common Voice, OpenSLR72, TinyVox, and TalkBank, follow the citation requirements on the linked source pages. In particular, SLR72 derives from Guevara-Rukoz et al., Crowdsourcing Latin American Spanish for Low-Resource Text-to-Speech (LREC 2020), and TinyVox is described by Charlot et al. (2025) and Lavechin, Bergelson, and Levy (2026).

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 bookbot/zipformer-streaming-robust-es-v1

Finetunes
1 model

Datasets used to train bookbot/zipformer-streaming-robust-es-v1

Collection including bookbot/zipformer-streaming-robust-es-v1