Views
No views yet
actableai/zipformer-rnnt-v2 and trained on
actableai/vi-meeting-soniox-wer16
with Soniox transcripts as golden labels.| Base | actableai/zipformer-rnnt-v2 (policy-domain Zipformer, BPE-3000) |
| Fine-tune data | Meeting segments with WER(Soniox, baseline Qwen) ≤ 16% |
| Labels | Soniox text only (mixed-case; not uppercased) |
| Params | ~70.7 M (transducer; no CTC head in this fine-tune) |
| Sample rate | 16 kHz, 80-dim log-Mel fbank (on-the-fly) |
session_soniox_dev.jsonl → 5,453 utterances, ~13.8 hgreedy_search_batchbest-valid-loss.pt using model_avg weights| Model | Meeting-dev WER | Errors / words |
|---|---|---|
v2 baseline (actableai/zipformer-rnnt-v2) | 31.07% | 56,369 / 181,450 |
| v3 (this model) | 20.71% | 37,580 / 181,450 |
| Δ absolute | −10.36 | — |
| Δ relative | −33.3% | — |
Measured 2026-07-27 witheval_zipformer_meeting_wer16.py(full meeting dev).
| Epoch | Valid loss | Simple | Pruned |
|---|---|---|---|
| 1 | 0.4787 | 0.4529 | 0.2577 |
| 2 | 0.3846 | 0.3782 | 0.1805 |
| 3 | 0.3605 | 0.3684 | 0.1725 |
| 4 | 0.3478 | 0.3633 | 0.1662 |
| 5 | 0.3433 | 0.3604 | 0.1631 |
| 6 | 0.3416 | 0.3589 | 0.1622 |
| 7 | 0.3398 | 0.3578 | 0.1609 |
| 8 | 0.3385 | 0.3565 | 0.1603 |
| 9 | 0.3369 | 0.3558 | 0.1590 |
| 10 (best) | 0.3362 | 0.3552 | 0.1586 |
| Split | Segments | Hours | Source |
|---|---|---|---|
| train | 22,693 | ~68.1 | actableai/vi-meeting-soniox-wer16 (= local session_soniox_train_filtered.jsonl) |
| dev | 5,453 | ~13.8 | session_soniox_dev.jsonl (Soniox labels) |
text only — never Qwen hypothesesfull_session.wav + start/end offsets)use_mux=0) — pure meeting wer16| Knob | Value |
|---|---|
| Recipe | icefall Zipformer2 finetune.py |
| Init | load encoder,encoder_embed,decoder,joiner,simple_am_proj,simple_lm_proj from v2 |
| CTC | disabled (use_ctc=0) — joint CTC FT was unstable (CTC bias grad explosion under fp16) |
| Optimizer | ScaledAdam + Eden LR schedule |
base_lr | 5e-4 |
| Epochs | 10 |
| Batching | max_duration=300 s / batch, dynamic bucketing |
| Precision | fp16 |
| Features | on-the-fly 80-dim Kaldi fbank |
| SpecAugment | on (time-warp factor 80) |
| MUSAN | off |
| Speed perturb | off |
| Seed | 42 |
| Hardware | 1× A100-SXM4-40GB |
| Global steps | ~8,674 |
| Param | Value |
|---|---|
num_encoder_layers | 2,2,3,4,3,2 |
encoder_dim | 192,256,384,512,384,256 |
downsampling_factor | 1,2,4,8,4,2 |
feedforward_dim | 512,768,1024,1536,1024,768 |
num_heads | 4,4,4,8,4,4 |
cnn_module_kernel | 31,31,15,15,15,31 |
encoder_unmasked_dim | 192,192,256,256,256,192 |
decoder_dim / joiner_dim | 512 / 512 |
| Vocab | BPE-3000 (mixed-case Vietnamese; same as v2) |
| File | Description |
|---|---|
best-valid-loss.pt | Best icefall checkpoint (model + model_avg + train metadata) |
bpe.model | SentencePiece BPE-3000 (shared with v2) |
tokens.txt | Token id map for sherpa / icefall |
config.json | Architecture + training metadata |
train_zipformer_meeting_wer16.sh | Launch script used for this run |
prep_lhotse_meeting_wer16.py | Lhotse CutSet prep (Soniox labels) |
eval_zipformer_meeting_wer16.py | Greedy WER eval helper |
1import torch, sys
2sys.path.insert(0, "/path/to/icefall")
3sys.path.insert(0, "/path/to/zipformer_work") # finetune.py / model defs
4
5from finetune import get_model, get_params, add_model_arguments
6from beam_search import greedy_search_batch
7import argparse, sentencepiece as spm
8
9parser = argparse.ArgumentParser()
10add_model_arguments(parser)
11params = get_params()
12params.update(vars(parser.parse_args([])))
13params.encoder_dim = "192,256,384,512,384,256"
14params.num_encoder_layers = "2,2,3,4,3,2"
15params.downsampling_factor = "1,2,4,8,4,2"
16params.feedforward_dim = "512,768,1024,1536,1024,768"
17params.num_heads = "4,4,4,8,4,4"
18params.cnn_module_kernel = "31,31,15,15,15,31"
19params.encoder_unmasked_dim = "192,192,256,256,256,192"
20params.decoder_dim = 512
21params.joiner_dim = 512
22params.causal = False
23params.vocab_size = 3000
24params.blank_id = 0
25params.context_size = 2
26params.use_transducer = True
27params.use_ctc = False
28
29model = get_model(params)
30ckpt = torch.load("best-valid-loss.pt", map_location="cpu")
31state = ckpt.get("model_avg") or ckpt["model"]
32model.load_state_dict(state, strict=False)
33model.eval().cuda()
34
35sp = spm.SentencePieceProcessor()
36sp.load("bpe.model")
37
38# feature: (1, T, 80) float32 fbank; feature_lens: (1,) int
39with torch.no_grad():
40 encoder_out, encoder_out_lens = model.forward_encoder(feature, feature_lens)
41 token_ids = greedy_search_batch(model, encoder_out, encoder_out_lens)
42text = sp.decode(token_ids[0])
43print(text)| Date | Event |
|---|---|
| 2026-07-27 | Fine-tune v2 → meeting wer16, 10 epochs; valid loss 0.479 → 0.336 |
| 2026-07-27 | Meeting-dev WER 31.07% (v2) → 20.71% (v3); push actableai/zipformer-rnnt-v3 |