跳到主要内容

语音识别工具链

Kaldi 本地部署,显存从来不是那堵墙

chain 声学模型只有几十 MB,一张 24GB 卡绰绰有余。真正决定你租哪张卡的,是 CUDA 批量解码能挂多少路并发,以及 configure 那串 gencode 认不认你的芯片。

Kaldi 是 WFST 语音识别的参考实现,2015 年落到 GitHub 上,至今 15.4k star、5.3k fork,Apache-2.0 协议。它有个和别的项目都不一样的地方:仓库里一个 release tag 都没有,版本号只写在 src/.version 这个文本文件里,内容就两个字符——5.5。Daniel Povey 一个人贡献了近 4000 次提交,然后把精力转向了别处;主线最后一次 push 停在 2025 年 9 月。但它没有被归档,Vosk(15k star,仍在更新)这类落地项目今天仍然直接跑在它上面。

所以搜「Kaldi 本地部署」的人,第一步得先确认自己说的是哪个 Kaldi。主线 kaldi-asr/kaldi 是 C++ 写的 WFST 工具箱,给你 GMM 强制对齐、HCLG 解码图、lattice 后处理、CUDA 批量解码器。Next-gen Kaldi 是另一套东西:k2 提供可微的 FSA/FST 算子,lhotse 管数据,icefall 放训练 recipe,sherpa-onnx 负责端侧推理——最新一版 v1.13.6 发在 2026 年 8 月 18 日,节奏跟主线完全是两回事。两条线共用一个名字,但代码没有一行是共享的。

至于显存,Kaldi 跟大模型那套换算完全不搭界。它的 chain 模型是 17 层 TDNN-F,dim 1536、bottleneck 160,落盘几十 MB,训练时单卡 8GB 都算宽裕。真正的资源墙有三道:特征抽取和对齐要横向 fan-out 吃 CPU 核;建 HCLG 图和 dump egs 吃内存与磁盘;只有 GPU 批量解码这一环是真吃显存——上游 cudadecoder/README 写得很直白,16GB 卡大约支撑 200 路并发,而且显存随控制线程数和 batch size 线性增长。按并发选卡,不要按参数量选卡。

01 —

Kaldi 家族对照表:你要装的到底是哪一个

主线 C++ 工具箱、Next-gen 训练栈、跨端推理运行时,三条线各有各的显存账。

版本参数量显存上下文说明
Kaldi 主线(kaldi-asr/kaldi,src/.version = 5.5)chain TDNN-F:17 层 × dim 1536 / bottleneck 160训练单卡 8GB 起步已宽裕;CUDA 解码 16GB ≈ 200 路并发WFST 全句解码,没有上下文窗口这个概念GitHub 上没有任何 tag 发布,版本号只在 src/.version 里;最后一次 push 是 2025-09-22。要 WFST 解码图、GMM 对齐、lattice 后处理,或者要复现论文里的 s5 recipe,只能用它。
k2(k2-fsa/k2)可微 FSA/FST 算子库,本身不含权重自身几乎不占;显存跟着 PyTorch 与 --max-duration 走Next-gen Kaldi 的计算内核,Apache-2.0,2026 年 7 月仍在更新。预编译 wheel 走 k2-fsa.github.io/k2/cuda.html,国内换成 cuda-cn.html;已经出到 ROCm 7.2 + PyTorch 2.12.1 的轮子。
icefall Zipformer-small23.3M(LibriSpeech)/ 30.17M(AISHELL-1)fp16,2 卡 × 32GB,--max-duration 1500(英)/ 1200(中)非流式整句;加 --causal 1 转 320ms chunk 流式LibriSpeech test-clean 2.42 / test-other 5.73,AISHELL-1 dev 4.67 / test 4.97。官方 RESULTS.md 记的就是两张 32G V100,是整条线上最省钱的复现起点。
icefall Zipformer(normal)65.55M(LibriSpeech)/ 73.41M(AISHELL-1)fp16,4 卡 --max-duration 1000,50 epoch非流式;流式版 66.11M,320ms chunkLibriSpeech test-clean 2.21 / test-other 4.79;流式 320ms 版 test-clean 2.79 / test-other 7.36。生产上最常被直接拿去上线的一档。
icefall Zipformer-large / CR-CTC148.4M(transducer)/ 147.0M(CR-CTC)/ 157.29M(AISHELL-1 large)CR-CTC 官方配置是 2 卡 × 80GB A100,--max-duration 1400非流式CR-CTC 把 LibriSpeech test-clean 压到 2.02、test-other 4.35,是这条线目前最好的一档。80GB 不是摆设——--max-duration 1400 在 32GB 卡上放不下。
sherpa-onnx v1.13.6推理运行时,不含权重CPU 即可跑;GPU 走 CUDA 12 + cuDNN 9,或 CUDA 13 + cuDNN 9 + onnxruntime 1.27.1随所加载的模型而定2026-08-18 发布,Apache-2.0。同一套 C++ 内核喂 Zipformer、Paraformer、SenseVoice、Whisper、Moonshine、TeleSpeech、Parakeet;从 Linux/Windows 一路覆盖到 Android、iOS、鸿蒙、树莓派、RISC-V 和各家 NPU。

02 —

选卡:按你要做的事,不是按参数量

Kaldi 的显存账和 LLM 完全不是一回事,别照搬那套「参数量 × 2 字节」的心算。

  • 编译带 CUDA 的 Kaldi,训练 chain / nnet3 模型

    RTX 3090 24GB$0.193/卡·时

    sm_86 就在 Kaldi configure 给 CUDA 12.x 的默认 gencode 列表里,一个字不用改就能编出来;chain 模型本体几十 MB,24GB 跑 num-chunk-per-minibatch 64 富余得很。

  • batched-wav-nnet3-cuda2 批量离线转写

    Tesla T4 16GB$0.298/卡·时

    上游 cudadecoder/README 的基准刻度就是 16GB 卡约 200 路并发(4 控制线程 × batch 50),T4 正好对上这个数,sm_75 也在默认 gencode 里。

  • 高并发转写集群,想按默认 --num-channels 600 直接跑

    RTX A6000 48GB$0.817/卡·时

    README 说显存随控制线程数与 batch size 线性放大,48GB 差不多能把默认的 --max-batch-size 400 / --num-channels 600 原样吃下,不用退档重调。

  • icefall Zipformer 复现训练与中文微调

    Tesla V100 32GB$0.188/卡·时

    icefall RESULTS.md 里 small(23.3M)和 CR-CTC medium(66.2M)两档就是两张 32G V100 训出来的,--world-size 2 的配置能一比一照抄;只有 --max-duration 1400 的 CR-CTC large 才真需要跳到 A100 PCIE 80GB($0.824/卡·时)。

03 —

四步把 Kaldi 在 NexGPU 上跑通

从 Ubuntu CLI 镜像开机,到 GPU 批量解码吐出 lattice。

  1. 01

    开实例,装依赖,编译带 CUDA 的 Kaldi

    选 Ubuntu CLI 或 PyTorch 镜像开机,SSH 进去先跑 check_dependencies.sh——它会点名 g++ ≥ 4.8.3、gfortran、zlib、sox、libtool、automake 这一串,缺哪个装哪个。tools/ 会顺手把 OpenFst 1.8.4 和 sph2pipe 编好。有个坑要提前避开:CUDA 12.x 要求 GCC 低于 12.3,Ubuntu 24.04 自带的 g++-13 会被 configure 直接顶回来,先装 g++-12 再用 CXX 指过去。仓库里那套 CMake 构建官方自己都写着「可能没有充分测试,部分功能缺失」,老老实实走 tools/ + src/ 这条路。

    cd kaldi/tools && extras/check_dependencies.sh && make -j$(nproc) && cd ../src && ./configure --shared --use-cuda=yes --cudatk-dir=/usr/local/cuda && make -j$(nproc) depend && make -j$(nproc)
  2. 02

    建解码图——chain 模型的头号翻车点

    mkgraph.sh 的 --self-loop-scale 默认值是 0.1,那是给老式 GMM / nnet3 用的。chain 模型必须传 1.0,脚本自己都会打出「WARNING: chain models need '--self-loop-scale 1.0'」,但这行警告太容易被刷屏刷掉,结果就是 WER 高得莫名其妙、查半天查不出原因。这一步吃 CPU 和内存,不吃显存:LG → CLG → HCLGa → HCLG 四段合成里,大 n-gram 的 determinize 是整条流水线的内存峰值,节点内存不够就在这里炸。

    utils/mkgraph.sh --self-loop-scale 1.0 data/lang_test_tgsmall exp/chain/tdnn_1d_sp exp/chain/tdnn_1d_sp/graph_tgsmall
  3. 03

    开 GPU 批量解码,并且先把默认值调下来

    batched-wav-nnet3-cuda2 的出厂默认是 --max-batch-size 400、--num-channels 600,而上游 README 只承诺 16GB 卡约 200 路并发——在 T4 上照默认跑必然爆显存。先按 4 控制线程 × batch 50 起步,实测稳定了再往上顶。另一个默认值同样反直觉:--cuda-use-tensor-cores 默认是 false,官方注释写明它启用 FP16 张量运算、只推荐用于推理,你不显式打开,T4 / A100 的张量核就一直闲着。还有 README 那句原话得记住:单条音频喂不满任何一张 NVIDIA GPU,必须并发。

    batched-wav-nnet3-cuda2 --cuda-use-tensor-cores=true --max-batch-size=50 --num-channels=200 --cuda-decoder-copy-threads=2 --frame-subsampling-factor=3 --acoustic-scale=1.0 final.mdl HCLG.fst scp:wav.scp ark:lat.ark
  4. 04

    要 SOTA 效果,切到 Next-gen Kaldi 这条线

    主线 Kaldi 在 AISHELL-1 上 chain 模型的 CER 是 7.48%,icefall 的 Zipformer-small 在同一测试集上是 4.97%,large 4.49%,CR-CTC 那档 3.98%。这个差距不是调参能补回来的。k2 的 wheel 国内直接换 -cn 镜像索引,训练命令照抄 RESULTS.md 就行;训完导出 ONNX,交给 sherpa-onnx 上线,同一套模型能一路铺到 Android、iOS 和鸿蒙。

    pip install k2 -f https://k2-fsa.github.io/k2/cuda-cn.html && ./zipformer/train.py --world-size 2 --num-epochs 60 --start-epoch 1 --use-fp16 1 --exp-dir zipformer/exp --max-duration 1200

一笔算得清的账

先说训练。icefall 官方 AISHELL-1 Zipformer-small 的配置是 --world-size 2 --num-epochs 60 --max-duration 1200,跑在两张 32GB V100 上。NexGPU 的 Tesla V100 32GB 是 $0.188/卡·时,两张就是 $0.376/时:连跑 48 小时 = $0.376 × 48 = $18.05,跑 72 小时 = $0.376 × 72 = $27.07。想把 --max-duration 顶上去换更短的墙钟时间,换两张 A100 PCIE 80GB($0.824/卡·时)= $1.648/时,同样 48 小时 = $79.10。 再说解码。主线 Kaldi 的 batched-wav-nnet3-cuda2 在一张 Tesla T4 16GB($0.298/时)上按上游刻度挂 200 路并发,连跑 24 小时 = $0.298 × 24 = $7.15;换 RTX A6000 48GB($0.817/时)把 --num-channels 顶到默认的 600,24 小时 = $19.61——路数翻三倍,单位并发成本反而更低。 最后是数据落盘。特征加 egs dump 按 200GB 算,存储 $0.414/GB·月 × 200 = $82.80/月,折合 $2.76/天。这里有个必须记住的规则:实例一停计算立刻停止计费,存储要销毁才停,所以 egs 跑完就清。出网 $0.0081/GB,把 400MB 的模型和 lattice 拷回本地是 0.4 × $0.0081 ≈ $0.003,四舍五入等于零。全程没有起租时长、没有开通费、不用申请配额。

04 —

常见问题

Kaldi 还在维护吗?2026 年还值得用吗?

主线仓库最后一次 push 停在 2025 年 9 月,GitHub 上从来没打过 release tag,版本号只写在 src/.version 里,是 5.5。Daniel Povey 贡献了近 4000 次提交之后把精力转到了 Next-gen Kaldi。但它没被归档,Vosk 这类落地项目今天仍然直接跑在它上面。判断标准很简单:你要 WFST 解码图、GMM 强制对齐、lattice 后处理,或者要一比一复现论文里的 s5 recipe,就用主线;你要的只是识别率,就上 icefall。两条路在 NexGPU 上是同一台机器、同一套镜像,按秒计费,把两条都试一遍的成本就是几美元。

Kaldi 本地部署到底需要多大显存?

训练侧几乎不构成问题——chain 的 TDNN-F 是 17 层 dim 1536、bottleneck 160,模型文件几十 MB,一张 RTX 3090 24GB($0.193/卡·时)绰绰有余。真正吃显存的是 CUDA 批量解码:上游 cudadecoder/README 给的刻度是 16GB 卡约 200 路并发,而且显存随控制线程数与 batch size 线性增长。所以正确的问法不是「Kaldi 要多大显存」,而是「我要挂多少路并发」。NexGPU 上 T4 16GB 和 A6000 48GB 都是现货,先开 T4 把你的真实并发量测出来,再决定要不要换大卡。

在 RTX 5090 上能编译 Kaldi 吗?

能,但不是开箱即用。Kaldi 的 configure 给 CUDA 12.x 的默认 gencode 列表是 sm_50 到 sm_90,最高只到 Hopper,Blackwell 的 sm_120 不在里面。你得自己传 --cuda-arch="-gencode arch=compute_120,code=sm_120",配一个支持 Blackwell 的 CUDA 版本,同时 GCC 还得低于 12.3。如果只想赶紧跑通,NexGPU 上的 RTX 3090(sm_86,$0.193/卡·时)或 A100 PCIE 80GB(sm_80,$0.824/卡·时)在默认列表里,configure 完直接 make。要折腾 RTX 5090 32GB($0.723/卡·时)我们也有现货,只是记得把编译时间留出来。

Kaldi 在中文 AISHELL 上的识别率是多少?和 Zipformer 差多远?

Kaldi 自带的 egs/aishell/s5 RESULTS 写得一清二楚:mono 36.41%,tri5a 12.12%,nnet3 tdnn_sp 8.65%,chain tdnn_1a_sp 7.48% CER。icefall 在同一个 AISHELL-1 上,Zipformer-small(30.17M)test CER 4.97%,normal(73.41M)4.67%,large(157.29M)4.49%,CR-CTC medium(66.2M)3.98%。错误率差了将近一半。中文场景要上生产,答案基本已经写在数字里了。NexGPU 的 Tesla V100 32GB $0.188/卡·时,两张卡就能照 icefall 的原始配置把它训出来。

batched-wav-nnet3-cuda2 跑起来 GPU 利用率很低,或者直接 OOM,怎么办?

两个典型原因。一是默认值太激进:--max-batch-size 默认 400、--num-channels 默认 600,远超 16GB 卡能承受的范围,先降到 batch 50、channels 200,稳了再往上试。二是张量核默认关着:--cuda-use-tensor-cores 默认 false,推理时要显式设成 true,FP16 张量运算才会真正参与。还有 README 那句原话——单条音频喂不满任何一张 NVIDIA GPU,必须靠并发把 GPU 灌满。在 NexGPU 上换卡不用重新申请配额、没有起租时长,T4、A6000、A100 挨个试一遍,成本也就一顿饭。

国内网络能顺利装上 k2 和 icefall 吗?

能。k2 官方就提供了国内镜像索引——把 wheel 源从 k2-fsa.github.io/k2/cuda.html 换成 cuda-cn.html 即可,CPU 版是 cpu-cn.html,AMD 卡走 rocm-cn.html(已经跟到 ROCm 7.2 + PyTorch 2.12.1)。真正麻烦的从来不是装包,是 LibriSpeech、AISHELL 这些数据集的下载速度和 lhotse 的特征抽取时长。NexGPU 在 51 个国家和地区有 1,175 个可租节点,你可以挑一个离数据源最近的机房开机,拉完数据再把实例停掉——计算立刻停止计费,存储留着,下次接着跑。

开始使用 NexGPU

无论你是企业研发团队还是独立开发者,都可以在几分钟内跑起第一个任务。

注册即可浏览全网实时价格,无需绑定支付方式。