ASR 模型选型实战:从一段全是噪音的录音说起
事情的起点
一批 8kHz 的无线通话录音要做转写。这个选型前后做了两轮:第一轮把市面上叫得上号的开源模型扫了一遍(七个本地模型 + 四家云端 API),第二轮圈定四款做批量集中验证。
第一天就撞上了第一个坑,而且是我自己挖的。
第一坑:PCM 根本不是一种格式
拿到的是一批无扩展名的裸音频文件,按”8kHz × 8bit = 64kbps”的直觉,我用无符号 8bit 线性 PCM 去解:
ffmpeg -f u8 -ar 8000 -ac 1 -i input.pcm output.wav解出来一听——噪音巨大,人声若有若无。我的第一反应是”源文件音质就这么差”。
直到有人拿配套的专用转换工具转了一版,同样源文件,听感明显干净。一个 14MB 的小工具能做到 ffmpeg 做不到的事?我不信。
strings 扫了一遍那个工具的核心 DLL,导出函数列表里躺着一行答案:
G729ToALawPcmtoWaveNewG729 转 A-law——这批录音是电信系统的 A-law 对数编码,根本不是线性 PCM。
对数编码和线性编码的区别可以抽象成一个通用模式:同一个字节值 b,在线性语义下表示”幅度就是 b”,在对数语义下表示”幅度是 exp(b) 的映射”。两套语义对小信号的处理完全不同——对数编码正是为了在 8bit 里塞下电话级动态范围设计的。你拿线性去解对数,等于拿对数表当加法表用,信噪比全乱,出来的”噪音”其实是被错误还原的语音。
换正确的解码方式:
ffmpeg -f alaw -ar 8000 -ac 1 -i input.pcm -c:a pcm_s16le output.wav听感和专用工具完全一致。顺带搞清了大小差异:它输出 8bit 我输出 16bit,同一段音频正好差一倍,内容零差别。
教训:遇到陌生的裸数据,先逆向它的配套工具,别凭参数直觉猜格式。 A-law(中国/欧洲电信)还是 μ-law(美日),这一步猜错,后面所有评测全部作废——我第一轮全量推理就是这么报废的。
第二坑:升采样不会提升质量
纠错过程中我还犯过另一个方向的错误:把 8kHz 升到 16kHz 再喂模型,理由是”主流模型都要 16kHz”。
错。奈奎斯特定理决定了 8kHz 录音里最高只有 4kHz 的频率信息,升采样不会凭空造出新信息,插值算法反而会把 8bit 的量化误差扩散到更多采样点上,信噪比更低。正确姿势是保持原生采样率,让模型内部的重采样逻辑自己处理——各家模型都带这一层。
当然有例外:个别开源模型(比如 FireRedASR2)要求外部喂 16kHz,那就单独转一份给它,但这是”喂给特定模型的适配层”,不是”提升音质”。
没有标注数据,怎么做评测?
这批录音没有人工转写的标准答案,算不了字错率(CER)。实际用的是两条腿走路:
交叉对比:多个模型转同一段音频,互为参照。所有模型都识别出的内容,大概率是对的;只有一个模型独有的内容,人工抽听裁决。
维度量化:把”识别质量”拆成可数的指标——
- 行业术语命中数(维护一张领域术语表,统计每家的命中次数)
- 地名/呼号识别(词表 + 正则)
- 文本输出量(平均/中位字数,过短=漏内容,过长=可能有幻觉)
- 成功率(失败、空输出单独计数)
- 速度(平均耗时、RTF=处理时间/音频时长)
测速还有个铁律:必须标注并发数和 batch size。 云端 API 开 5 个并发和串行,吞吐天差地别;本地模型 batch=1 和 batch=8 也不是一回事。我第一版报告只写了”平均 X 秒”,被自己人一句”你到底并发了几个”问穿——没有并发标注的速度数据,等于没测。
第一轮:基准排名会骗人
第一轮扫描覆盖了七个本地开源模型:FireRedASR2-LLM、FireRedASR2-AED、Qwen3-ASR-1.7B、FunASR-Nano、SenseVoice-L、Paraformer-Large、Whisper-Large-v3,外加豆包/讯飞/腾讯云/阿里云四家云端。先看各论文在标准 16kHz 测试集上的普通话 CER:
| 模型 | 基准CER% |
|---|---|
| FireRedASR2-LLM | 2.89 |
| FireRedASR2-AED | 3.05 |
| 豆包ASR | 3.69 |
| Qwen3-ASR-1.7B | 3.76 |
| FunASR-Nano | 4.16 |
| SenseVoice-L | 4.47 |
| Paraformer-Large | 4.56 |
| Whisper-Large-v3 | 9.86 |
拿同一段真实的 8kHz 低质量通话音频喂进去,排名反转了:基准第四的 Qwen3-ASR 实测最优——专业词汇最准、转写最完整通顺;基准第一的 FireRedASR2 鲁棒性反而略逊,出现了把”夜航资质”听成”银行资质”这类领域词错误。
这一轮最大的教训就一句话:基准测试集是 16kHz 干净音频,你的业务音频是另一回事,选型必须拿真实数据实测。
初筛还抓到几种有意思的失效模式,值得记录:
- 重复循环:Qwen3-ASR 和 Whisper Turbo 在噪声段陷入复读,同一个词组输出几百次(Whisper 还顺手切成了繁体中文)
- 整体乱码:Paraformer 在这批音频上输出完全不可读
- 同门几乎一致:FireRedASR2 标准版和 Lite 版输出几乎逐字相同,买大不买小没有意义
另外做了个底座核查,结论对选型很有参考价值:榜单上的高分”新”模型,大量是开源底座的衍生品。核查方法很简单——抓 HuggingFace 模型仓库的 raw README(详情页是 SPA,curl HTML 拿不到内容)。核查结果:MOSS-Transcribe 是 Qwen3-1.7B 底座 + Qwen3-Omni 音频编码器;Higgs Audio v3 是 Whisper-Large-v3 编码器 + Qwen3 解码器;某排行榜第 10 名的模型点开详情一看,“基于千问 1.7B 微调”。所以追赶榜单之前,先看看它爹是谁。
第二轮:四款集中验证
第二轮圈定四款:Qwen3-ASR 与 FireRedASR2 本地部署、讯飞与豆包云端 API,用批量的真实数据(100 个常规文件 + 两批各 10 个长音频)集中验证。维度量化结果:
| 维度 | Qwen3-ASR | FireRedASR2 | 讯飞 | 豆包 Seed |
|---|---|---|---|---|
| 部署 | 本地 GPU | 本地 GPU | 云端 API | 云端 API |
| 成功率 | 99% | 81%~70% | 99% | 86%(限流所致) |
| 行业术语 | 多 | 少 | 最多 | 多 |
| 处理速度(RTF,越小越快) | 0.20 | 0.12 | 0.70 | 0.40 |
| 词级时间戳 | 需额外对齐模型 | 原生支持 | — | — |
| 数字输出 | 汉字(需后处理) | 汉字 | 汉字+阿拉伯混合 | 自带阿拉伯数字 |
几个值得展开的点:
FireRedASR2 被稳定性淘汰。 它推理最快、原生带词级时间戳和置信度评分,设计上很优雅。但常规批 19% 的文件输出空文本,换一批长音频又随机挂掉三个——置信度掉到 0.07,其他三家都识别得完整。测试结束后我把它从服务器上删了,理由就一个:ASR 是个流水线零件,零件可以慢,不能随机坏。
豆包的限流很严。 并发 3 就开始批量 429,1140 个文件的单线程补跑花了好几个小时。它的 API 是两步式(提交任务+轮询结果),认证信息全放 HTTP Header,网上能搜到的旧版端点基本都 404 或 403,照着官方文档的 v3 路径走才通。
讯飞的语种参数是 cn 不是 zh。 这个坑值得单独写一行:报”转写语种未授权”先检查语种代码,中国区普通话的代码是 cn。另外它的签名放在请求头而不是 URL 参数,音频要发原始二进制——base64 会触发文件大小校验不一致。
LLM 系 ASR 的数字问题
Qwen3-ASR 识别准确率很高,但所有数字都输出汉字:“三四三四”而不是”3434”。这对通话类场景是硬伤——呼号、编号、高度值都需要阿拉伯数字。
第一反应是加提示词:“所有数字用阿拉伯数字表示”。实测两种提示词的输出逐字节相同。原因在于 LLM 系 ASR 是音频驱动的转写器,说话人怎么读它就怎么写,文字提示控制不了输出格式。云端 API 没这个问题是因为服务端内置了 ITN(逆文本规范化)。
解法是本地后处理,配方三件套:
- cn2an 的 smart 模式处理量词式读法(“三百”→300,“十二点”→12点)
- 逐位映射表处理逐字读法(幺=1、两=2、拐=7、洞=0——行业读法里 0 读”洞”)
- 贪心分段处理混合读法:“六百三零幺六”整体解析会失败,拆成 cn2an 能吃的最长前缀(六百三→630)加逐位尾巴(零幺六→016),拼出 630016
还有两个防御性细节:末尾的”点”是钟点语义(“十二点”→“12点”),要防着被当小数点吞掉;“一起”、“统一”这类含数字字的常用词不能误伤。
显存与内存:实测数字
部署前总得回答”多大的卡能跑”。用 120 秒的长音频把流程压满实测(bf16 精度):
| 场景 | 显存峰值 | 内存峰值 |
|---|---|---|
| 纯转写 | 4.68 GB | 4.76 GB |
| 转写+词级时间戳 | 6.40 GB | 4.99 GB |
结论:满血(转写+时间戳)8G 显存起步,内存 8G 稳妥;纯转写 6G 显存够用;4G 显存或 4G 内存的机器跑不动——权重本身 bf16 就 3.4GB,加上 CUDA 上下文和激活值必然爆。
顺带修了一个自己的惯性错误:一开始用 fp32 跑(显存直接翻倍),其实 bf16 加一行输入特征类型转换就完全正常,输出质量一致、速度更快。
最后的选型答案
两轮跑完,答案收敛得很干净:
- 数据不能出域 / 无网络环境:Qwen3-ASR 本地部署,配上数字后处理和时间戳对齐模型,功能闭环
- 要省事、要准确率:讯飞云端,术语识别最多、稳定 99%
- 要阿拉伯数字原生输出:豆包,但要接受单线程限流
- 没有 GPU、纯 CPU 跑:SenseVoice-Small 或 Paraformer(第一轮结论,轻量场景够用)
- 不想部署也不想挑模型:直接走大厂托管 API
- FireRedASR2:速度快,但随机空输出这个性质决定了它不适合做生产流水线零件
这次评测最大的收获反而不是选型结论,而是三条方法论:遇到陌生数据格式先逆向配套工具;基准排名会骗人,选型必须拿真实业务音频实测(基准第一的模型在我们的数据上被反超,最后还因稳定性出局);以及没有标注数据时,多维交叉对比照样能收敛出可信结论。至于那个让我第一轮全量报废的 A-law——下次再见到 8kHz 的”PCM”,我会先 strings 一眼再动手。
关联
- 检阅报告(内网):四模型横向对比页,含音频播放与分段可点时间轴
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!







