kangkyu's picture
Upload folder using huggingface_hub
db24b58 verified
|
Raw
History Blame Contribute Delete
8 kB
metadata
language:
  - ko
license: apache-2.0
tags:
  - automatic-speech-recognition
  - zipformer
  - transducer
  - causal
  - icefall
  - k2
  - korean
datasets:
  - ksponspeech
metrics:
  - cer
pipeline_tag: automatic-speech-recognition

icefall-asr-ko-streaming-zipformer-72m (ํ•œ๊ตญ์–ด)

๐Ÿ“– English README

icefall ๋ ˆ์‹œํ”ผ๋กœ ํ•™์Šตํ•œ 71.4M ํŒŒ๋ผ๋ฏธํ„ฐ ํ•œ๊ตญ์–ด causal ASR.

  • ํ•™์Šต ๋ฐ์ดํ„ฐ: KsponSpeech, ์•ฝ 1,000์‹œ๊ฐ„
  • KsponSpeech eval CER (๊ตฌ๋‘์  ๋ฌด์‹œ, CPU ์ถ”๋ก )
    • 7.68% โ€” offline best (chunk=โˆ’1 PyTorch + KenLM, RTF 0.057)
    • 8.25% โ€” streaming best (sherpa-onnx int8 chunk-64, RTF 0.038)
  • ๋ฐฐํฌ ๊ตฌ์„ฑ: PyTorch .pt + sherpa-onnx int8 ONNX (chunk 16/32/64, ๋ณ„๋„ export ์—†์ด ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)

๋ชจ๋ธ ์ •๋ณด

icefall Zipformer transducer ๊ธฐ๋ฐ˜.

  • causal ๊ตฌ์กฐ (chunk-16 / 32 / 64 / -1 multichunk ํ•™์Šต)
  • ํ•œ๊ตญ์–ด ์Œ์ ˆ vocabulary (2,460 ํ† ํฐ)
  • FP16 ํ•™์Šต
  • ๋ฐฐํฌ ํŒŒ์ผ: PyTorch epoch-99.pt (3-way state-dict avg, 273 MB) + sherpa-onnx int8 ONNX 9๊ฐœ (chunk 16/32/64 ร— encoder/decoder/joiner). ๋ณ„๋„ export ์—†์ด ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

์„ฑ๋Šฅ (KsponSpeech eval, CER %, ๊ตฌ๋‘์  ๋ฌด์‹œ)

eval_clean 3,000 + eval_other 3,000 = 6,000 cuts. ๋™์ผ ์…‹, beam=8, 3-way state-dict avg.

๋””์ฝ”๋”ฉ ๋ชจ๋“œ โ€” latency ์˜ˆ์‚ฐ์— ๋”ฐ๋ผ ์„ ํƒ

๋ชจ๋“œ chunk clean other OVR RTF latency
chunk=โˆ’1 PyTorch + KenLM ฮป=0.10 (offline best) โˆ’1 7.63 7.72 7.68 0.057 (CPU 2t) ๋ฐœํ™” ๋ ๋Œ€๊ธฐ
sherpa-onnx int8 chunk-64 64 8.28 8.22 8.25 0.038 (CPU 1t) 1.28์ดˆ
sherpa-onnx int8 chunk-32 32 8.45 8.33 8.39 0.039 (CPU 1t) 640ms
sherpa-onnx int8 chunk-16 16 8.63 8.64 8.635 0.052 (CPU 1t) 320ms

streaming ์ธก์ •์€ trailing padding 1x (CHUNK * 0.04 ์ดˆ) ๊ธฐ์ค€. RTF๋Š” clean/other ํ‰๊ท .

chunk=โˆ’1 (offline best 7.68%)๋Š” PyTorch ์ „์šฉ: sherpa-onnx๋Š” streaming chunk(16/32/64)๋งŒ ์ง€์›. offline ์ตœ๊ณ  ์ •ํ™•๋„๊ฐ€ ํ•„์š”ํ•˜๋ฉด epoch-99.pt๋ฅผ icefall recipe๋กœ ์ง์ ‘ ๋””์ฝ”๋”ฉ โ€” ์•„๋ž˜ "Option 1 โ€” PyTorch (epoch-99.pt) + icefall recipe" ์„น์…˜ ์ฐธ๊ณ .

์–‘์žํ™” ์•ˆ์ „์„ฑ โ€” fp32 vs int8 โญ

๊ฐ™์€ KsponSpeech 6,000 cut eval, ๋™์ผ 1x padding, CPU 1-thread ์ง์ ‘ sweep:

chunk fp32 OVR int8 OVR ฮ” CER fp32 RTF int8 RTF speedup
16 8.645 8.635 โˆ’0.010 0.078 0.052 1.50ร—
32 8.340 8.390 +0.050 0.060 0.039 1.54ร—
64 8.115 8.250 +0.135 0.057 0.038 1.50ร—

int8 ์–‘์žํ™” ํ›„์—๋„ ์ •ํ™•๋„๊ฐ€ ์‚ฌ์‹ค์ƒ ๋ณด์กด๋จ (ํ‰๊ท  ฮ” +0.06%p, ์ตœ๋Œ€ +0.135). CPU ์ถ”๋ก  ์†๋„๋Š” ~1.5๋ฐฐ ๋นจ๋ผ์ง โ€” ๊ทธ๋ž˜์„œ ๋ฐฐํฌ๋Š” .int8.onnx๋งŒ ํฌํ•จ. fp32๊ฐ€ ํ•„์š”ํ•˜๋ฉด epoch-99.pt์—์„œ icefall recipe๋กœ ์žฌexport.

๊ฐ™์€ ํ™˜๊ฒฝ์—์„œ ์ง์ ‘ ์ธก์ •ํ•œ ๋น„๊ต (KsponSpeech eval 6,000 cuts)

๋ชจ๋ธ params clean other OVR
๋™๋ฐ˜ 174M ๋ชจ๋ธ 155.7M 7.18 7.14 7.16
๋ณธ ๋ชจ๋ธ (72M) 71.4M 7.63 7.72 7.68
Qwen3-ASR-1.7B (Alibaba) 1,700M 9.76 10.22 9.99
OpenAI Whisper-large-v2 1,550M 13.70 12.64 13.17

๋ชจ๋“  ๋ชจ๋ธ์„ ๊ฐ™์€ KsponSpeech eval ์…‹์—์„œ ์ง์ ‘ ์ธก์ •. Whisper / Qwen ์€ GPU FP16 transformers ๊ธฐ๋ณธ ์˜ต์…˜, ๋ณธ ๋ชจ๋ธ์€ chunk=โˆ’1 PyTorch + KenLM rescore.

๋””์ฝ”๋”ฉ stack ๋‹จ๊ณ„๋ณ„ ํšจ๊ณผ

Stack clean other OVR
epoch-40 ๋‹จ์ผ, LM ์—†์Œ 8.11 8.06 8.08
3-way state-dict avg, LM ์—†์Œ 7.81 7.84 7.83
3-way avg + KenLM ฮป=0.10 (์œ„ ํ‘œ์˜ ์ธก์ • stack) 7.63 7.72 7.68

3-way avg = best-valid + best-train + epoch-40 ์˜ state_dict ํ‰๊ท .

์•„ํ‚คํ…์ฒ˜

Encoder Zipformer2 causal, 6 stacks
Encoder dim 192,256,384,512,384,256
Encoder layers 2,2,3,4,3,2
Feedforward dim 512,768,1024,1536,1024,768
Heads 4,4,4,8,4,4
Decoder Stateless transducer decoder, dim 512
Joiner dim 512
Vocabulary ํ•œ๊ตญ์–ด ์Œ์ ˆ, 2,460 ํ† ํฐ
์ด ํŒŒ๋ผ๋ฏธํ„ฐ 71.4 M
Causal Yes
ํ•™์Šต chunk-size 16, 32, 64, โˆ’1 multichunk

ํ•™์Šต

๋ฐ์ดํ„ฐ KsponSpeech 1,000์‹œ๊ฐ„ (AIHub dataset 123)
์ •๋ฐ€๋„ FP16
Loss Pruned-RNNT + CTC aux (scale 0.2)
Augmentation SpecAugment (musan/RIR optional)
Optimizer ScaledAdam
์ด epoch 40
๋ฐฐํฌ checkpoint best-valid + best-train + epoch-40 ์˜ 3-way state_dict ํ‰๊ท 

์‚ฌ์šฉ

Option 1 โ€” PyTorch (epoch-99.pt) + icefall recipe

icefall recipe (egs/librispeech/ASR/zipformer)๋กœ ๊ฐ€์ค‘์น˜๋ฅผ ๋กœ๋“œํ•˜์—ฌ ์ถ”๋ก . chunk size, beam, KenLM, ONNX export, ์–‘์žํ™” ๋“ฑ์€ ์ž์œ ๋กญ๊ฒŒ ์กฐ์ •.

chunk=โˆ’1 (offline best 7.68%) ์‹คํ–‰ ์˜ˆ์‹œ:

# epoch-99.pt๋ฅผ icefall exp dir์˜ epoch-99.pt๋กœ ๋‘๊ณ  ์‹คํ–‰
python zipformer/decode.py \
    --epoch 99 --avg 1 --use-averaged-model 0 \
    --causal 1 --chunk-size -1 --left-context-frames -1 \
    --decoding-method modified_beam_search --beam-size 8

KenLM rescore (ฮป=0.10) ์ถ”๊ฐ€ํ•˜๋ฉด 7.68% ์žฌํ˜„ ๊ฐ€๋Šฅ. ์ž์„ธํ•œ ์˜ต์…˜ยทKenLM ์‚ฌ์šฉ๋ฒ•์€ icefall ๊ณต์‹ ๋ฌธ์„œ ์ฐธ๊ณ .

Option 2 โ€” sherpa-onnx ์ŠคํŠธ๋ฆฌ๋ฐ (CPU ๋ฐฐํฌ ๊ถŒ์žฅ)

# ์„ค์น˜: pip install sherpa-onnx soundfile
import sherpa_onnx
import soundfile as sf

# chunk ์„ ํƒ: 16 (320ms ์ง€์—ฐ) / 32 / 64
# variant ์„ ํƒ: ".int8" (๋ฐฐํฌ ํฌํ•จ โ€” ํฌ๊ธฐ ~1/2, CER ์†์‹ค ๊ฑฐ์˜ ์—†์Œ)
#               "" (fp32, ๋ฐฐํฌ ๋ฏธํฌํ•จ โ€” ํ•„์š”์‹œ epoch-99.pt์—์„œ ์žฌexport)
CHUNK = 16
VARIANT = ".int8"

recognizer = sherpa_onnx.OnlineRecognizer.from_transducer(
    encoder=f"encoder-epoch-99-avg-1-chunk-{CHUNK}-left-128{VARIANT}.onnx",
    decoder=f"decoder-epoch-99-avg-1-chunk-{CHUNK}-left-128{VARIANT}.onnx",
    joiner=f"joiner-epoch-99-avg-1-chunk-{CHUNK}-left-128{VARIANT}.onnx",
    tokens="tokens.txt",
    num_threads=2,
    sample_rate=16000,
    feature_dim=80,
    decoding_method="modified_beam_search",
    max_active_paths=8,
)

audio, sr = sf.read("speech.wav")
stream = recognizer.create_stream()
stream.accept_waveform(sr, audio)
# ๋งˆ์ง€๋ง‰ chunk๊ฐ€ ์™„์ „ํžˆ ๋””์ฝ”๋“œ๋˜๋„๋ก ๋์— silence padding
import numpy as np
stream.accept_waveform(16000, np.zeros(int(CHUNK * 0.04 * 16000), dtype=np.float32))
stream.input_finished()
while recognizer.is_ready(stream):
    recognizer.decode_stream(stream)
print(recognizer.get_result(stream))

Chunk size ์„ ํƒ ๊ฐ€์ด๋“œ

chunk latency OVR ์šฉ๋„
16 320 ms 8.635 ์‹ค์‹œ๊ฐ„ UX, ์ตœ์ € interactive ์ง€์—ฐ
32 640 ms 8.39 ๊ท ํ˜•
64 1.28 s 8.25 ์ŠคํŠธ๋ฆฌ๋ฐ best CER (offline 7.68 ๋Œ€๋น„ +0.57)

ํŒŒ์ผ ๊ตฌ์„ฑ

epoch-99.pt                                                  # PyTorch 3-way state_dict avg (273 MB)
tokens.txt                                                   # ์Œ์ ˆ vocab 2,460
README.md / README_ko.md
encoder-epoch-99-avg-1-chunk-{16,32,64}-left-128.int8.onnx   # int8 encoder
decoder-epoch-99-avg-1-chunk-{16,32,64}-left-128.int8.onnx
joiner-epoch-99-avg-1-chunk-{16,32,64}-left-128.int8.onnx

๋™๋ฐ˜ ๋ชจ๋ธ

โ†’ icefall-asr-ko-streaming-zipformer-174m โ€” 155.7M params, KSP + AIHub 6,500์‹œ๊ฐ„ ํ•™์Šต.

๋ผ์ด์„ ์Šค

Apache 2.0.

Citation

@misc{ko-zipformer-72m,
  title  = {icefall-asr-ko-streaming-zipformer-72m: Korean ASR (KsponSpeech)},
  author = {Ken (kangkyu)},
  year   = {2026},
  howpublished = {\url{https://huggingface.co/kangkyu/icefall-asr-ko-streaming-zipformer-72m}}
}

๊ธฐ๋ฐ˜: