AigizK/GigaAM-Bashkir-CV25-ONNX
GigaAM Bashkir ASR — ONNX
ONNX Runtime export of `AigizK/GigaAM-Bashkir-CV25`, a character-level CTC ASR model for Bashkir (Башҡорт теле). The source model was fine-tuned from GigaAM Multilingual multilingual_ssl on Mozilla Common Voice 25 Bashkir.
Results
Raw WER is computed after lowercasing and punctuation removal on the complete Common Voice 25 splits, using onnx-asr with batch size 32.
Validation contains 14,525 clips (19.467 hours); test contains 14,572 clips (19.885 hours). See evaluation_results.json for exact error counts, hashes, providers, and runtime measurements.
Installation
CPU:
pip install "onnx-asr[cpu,hub]>=0.12,<0.13"NVIDIA CUDA for FP32:
pip install "onnx-asr[hub]>=0.12,<0.13" onnxruntime-gpuUsage
FP32
import onnx_asr
model = onnx_asr.load_model("AigizK/GigaAM-Bashkir-CV25-ONNX")
print(model.recognize("bashkir_audio.wav"))INT8 on CPU
import onnx_asr
model = onnx_asr.load_model("AigizK/GigaAM-Bashkir-CV25-ONNX", quantization="int8")
print(model.recognize("bashkir_audio.wav"))NVIDIA GPU
import onnx_asr
model = onnx_asr.load_model(
"AigizK/GigaAM-Bashkir-CV25-ONNX",
providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
)
print(model.recognize("bashkir_audio.wav"))Dynamic INT8 contains ConvInteger/MatMulInteger operators and is intended for CPU. Use FP32 with the CUDA Execution Provider on NVIDIA GPUs.
Batch recognition
Passing a list performs one padded batch and is substantially faster on GPU:
texts = model.recognize([
"audio_01.wav",
"audio_02.wav",
"audio_03.wav",
"audio_04.wav",
])
for text in texts:
print(text)Group recordings of similar duration to reduce padding overhead.
Configure CPU threads
import onnx_asr
import onnxruntime as ort
options = ort.SessionOptions()
options.intra_op_num_threads = 16
options.inter_op_num_threads = 1
model = onnx_asr.load_model(
"AigizK/GigaAM-Bashkir-CV25-ONNX",
quantization="int8",
providers=["CPUExecutionProvider"],
sess_options=options,
)Parallel requests with one shared model
from concurrent.futures import ThreadPoolExecutor
files = ["audio_01.wav", "audio_02.wav", "audio_03.wav", "audio_04.wav"]
with ThreadPoolExecutor(max_workers=4) as pool:
texts = list(pool.map(model.recognize, files))For maximum GPU throughput, prefer a real batch over concurrent batch-1 calls.
NumPy waveform / non-WAV audio
The built-in path reader accepts mono PCM WAV. Decode MP3/FLAC with an audio library and pass a float32 NumPy array:
import soundfile as sf
waveform, sample_rate = sf.read("bashkir_audio.flac", dtype="float32")
text = model.recognize(waveform, sample_rate=sample_rate, channel="mean")
print(text)Token timestamps and log probabilities
timestamped_model = model.with_timestamps()
result = timestamped_model.recognize("bashkir_audio.wav")
print(result.text)
print(result.tokens)
print(result.timestamps)
print(result.logprobs)Long audio with VAD
import onnx_asr
vad = onnx_asr.load_vad("silero")
longform_model = model.with_vad(vad)
for segment in longform_model.recognize("long_bashkir_audio.wav"):
print(segment.start, segment.end, segment.text)CLI
onnx-asr AigizK/GigaAM-Bashkir-CV25-ONNX bashkir_audio.wavonnx-asr accepts mono PCM WAV paths directly. It also accepts a float32 NumPy waveform and a sample_rate argument when audio is decoded by another library. The output is lowercase Bashkir text without punctuation.
Performance benchmark
Higher × realtime is better: 100× means 100 seconds of audio are processed in one second. Audio was decoded to mono 16 kHz and preloaded into RAM. Timed sections include feature extraction, ONNX inference, and greedy CTC decoding; Hub download, model loading/graph optimization, MP3 decoding, and disk I/O are excluded.
Hardware and software:
- AMD EPYC 7452, 32 physical cores / 64 threads
- NVIDIA GeForce RTX 3090 24 GB
- NVIDIA GeForce RTX 5090 32 GB
onnx-asr 0.12.0, ONNX Runtime 1.23.2, Python 3.11- deterministic, evenly spaced rows from Common Voice 25 Bashkir test
Batch size
Same 96 clips / 466.704 seconds of audio for every row. CPU uses 32 ONNX Runtime intra-op threads. GPU uses the CUDA Execution Provider.
CPU intra-op thread scaling
Batch size 8; same 24 clips / 117.324 seconds of audio.
Parallel batch-1 requests
One shared model, Python ThreadPoolExecutor, same 32 clips / 158.580 seconds. CPU sessions use 8 intra-op threads.
Key observations:
- RTX 5090 reaches about 1844× realtime at batch 32; RTX 3090 reaches about 745×.
- Batching is much more effective than concurrent batch-1 calls on GPU.
- On this EPYC, FP32 is faster than dynamic INT8. INT8's main benefit here is the 4× smaller artifact and lower memory/storage usage; speed depends on CPU instruction support and ONNX Runtime kernels.
- Four parallel CPU requests reach about 54× realtime FP32 and 59× INT8 aggregate throughput.
- Results are hardware- and workload-specific. Benchmark your expected audio lengths and concurrency.
Full-precision values and methodology are in benchmark_results.json; the reproducible runner is benchmark_onnx.py.
Artifacts
multilingual_bashkir_ctc.onnx: FP32 encoder and 43-class CTC head.multilingual_bashkir_ctc.int8.onnx: dynamic unsigned INT8 quantization for CPU.multilingual_vocab.txt: 42 Bashkir characters plus CTC blank at index 42.config.json: model configuration used byonnx-asr.benchmark_results.json: complete CPU/GPU benchmark output.benchmark_onnx.py: reproducible benchmark runner.
INT8 was produced with ONNX Runtime dynamic quantization, using unsigned 8-bit weights and activations with per-tensor scales. FP32 was evaluated with the CUDA Execution Provider; INT8 was evaluated with the CPU Execution Provider.
Limitations
- Trained and evaluated on read speech from Common Voice; conversational and noisy speech may differ.
- Greedy CTC decoding only; no external language model.
- No capitalization or punctuation prediction.
License
MIT License. Commercial use, modification, redistribution, and private use are permitted. Retain the copyright and license notice when redistributing.
