AI音频研究头像
关注
ASR 五代演进(七):开源模型推理与云端 ASR 横评封面图

ASR 五代演进(七):开源模型推理与云端 ASR 横评

本篇是「ASR 五代演进」系列第 7 篇 · 收官篇。前六篇拆完了五代 ASR 的架构演进——从 GMM-HMM 到 Audio LLM。这一篇只讲怎么调——每代给出直接可用的推理代码(流式 + 非流式)+ 真跑出来的 CER / RTF / 显存 / 首字延迟数字。目标是把不同代际的代表模型放到同一套测试语料和指标里量

测试语料(4 条 · edge-tts 合成 · 16 kHz mono · zh-CN-XiaoxiaoNeural 女声 · 中英混合):

名称时长内容特点参考文本(节选)
demo_mixed9.7sCN+EN + 数字 + % + 缩写Hello world, 欢迎收听 ASR 五代演进, 25 年 WER 从 13% 降到 1.5%, thanks!
demo_mixed_hard26.6s技术密度高 · 大量模型名 + 数字大家好,今天讲 Conformer-Transducer 的 RTF 优化……batch size 从 16 提到 64,端到端延迟从 320 毫秒降到 180 毫秒……
demo_mixed_conv20.0s口语对话 · 语气词 + 密切 CN/EN 切换哎,我跟你说啊,昨天开会讨论 GPT-4o 和 Seed-ASR 的 pk,emmm 说实话我觉得 Qwen2-Audio 也挺能打的……
demo_mixed_noisy9.7sdemo_mixed + 白高斯噪声 SNR = 5 dB同上 · 噪声鲁棒性压力测试

运行环境:本地开源模型在单张 24 GB 显存消费级 GPU 上测试 · Gen 2 Emformer-RNN-T 走 torchaudio 官方推理路径(部分算子在 CPU 上执行)· Gen 5 Seed-ASR 走火山云端 HTTP(wall time 含网络往返 · 不与本地 RTF 直接比较)。

模型清单(15 个非流式模型 + 3 组流式测试 · 覆盖 Gen 2-5 · Emformer 同一 checkpoint 两种接口都跑):

流式模型(chunk feed · 记录首字延迟):

模型参数首字延迟说明
Gen 2 · RNN-TEmformer-RNN-T (torchaudio)~80 M137-248 mssegment 640 ms · decoder.infer(state, hypothesis) 增量 · LibriSpeech 英文
Gen 4 · 非自回归FunASR · paraformer-zh-streaming~220 M~615 ms阿里 · chunk-attention · 4 条实测 CER 0.30-0.60
Gen 4 · TransducerWeNet · wenetspeech chunk~150 M~1.04 sPython 高阶 API 累积 500 ms chunk · CER 0.62-0.90

非流式测试(整段送入 · 记录 CER + wall time):

模型参数说明
Gen 2 · RNN-TEmformer-RNN-T~80 M架构原生 · 本篇整段离线 · torchaudio 官方 · LibriSpeech 英文
Gen 3 · SSLwav2vec2-large-960h-lv60-self300 M架构非流式(双向)· 整段 · HF · facebook · 英 CTC
Gen 3 · SSLwav2vec2-conformer-rope-large-960h-ft618 M架构非流式(双向)· 整段 · HF · facebook · 英 Conformer-CTC
Gen 3 · SSLwav2vec2-xlsr53-chinese-zh-cn315 M架构非流式(双向)· 整段 · HF · jonatasgrosman · 中 CTC
Gen 4 · 弱监督whisper-tiny39 M架构非流式(30s log-mel)· 整段 · HF · openai · 多语最小档
Gen 4 · 弱监督whisper-base74 M架构非流式(30s log-mel)· 整段 · HF · openai · 端侧 sweet spot
Gen 4 · 弱监督whisper-medium769 M架构非流式(30s log-mel)· 整段 · HF · openai · 桌面级
Gen 4 · 弱监督whisper-large-v31.55 B架构非流式 · 本篇整段送入 · HF · openai · 官方旗舰
Gen 4 · 弱监督faster-whisper-lv3 (int8)1.55 B架构非流式 · 整段 · HF · Systran · CTranslate2 · int8
Gen 4 · 弱监督distil-whisper-lv3756 M架构非流式 · 整段 · HF · distil-whisper · 英优先
Gen 4 · 非自回归FunASR · Paraformer-zh~220 M本篇非流式版(有独立 streaming 变体 · 未测)· 整段 · 阿里 · 单遍解码 · 中文首选
Gen 4 · 多语FunASR · SenseVoice-Small~200 M架构非流式 · 整段 · 阿里 · 多语 · 情感 + 事件标签
Gen 5 · Audio LLMQwen2-Audio-7B-Instruct7 B架构非流式 · 整段 · HF · Qwen · 一模型多任务 · Prompt 驱动
Gen 5 · 云端Seed-ASR (arkcli · doubao-seed-2-0-lite-260428)未公开arkcli 通用入口 · 整段 HTTP · 火山方舟 · Doubao Seed 2.0 lite audio LLM
Gen 5 · 云端Seed-ASR 2.0 专用引擎 (volc.seedasr.auc)未公开本篇走整段 HTTP submit + query · 火山 openspeech · X-Api-Key + REST · 权重不开源

未纳入实测的能力参照:GPT-4o Realtime(OpenAI · 实时全双工语音对话能力参照)· Gen 1 · Kaldi chain DNN-HMM(无可 in-process 直接跑的官方 checkpoint · 想复现要自训 + 部署解码图)。

评测口径(决定本篇所有 CER 数字含义): - CER 定义:先按下条归一化规则处理字符串 · 归一化后残留的字符逐字符计算编辑距离 / 参考文本字符数 - 归一化:小写化 · 剥除 space + 中英标点 + % · 不做繁简转换 · 不做数字文字统一(“25” ≠ “二十五”)· 不剥离 SenseVoice <|zh|> / <|HAPPY|> 等标签 · 剥离 Qwen2-Audio 常见 preamble("The transcription of the audio is:..." / "The complete transcription is:..." 等 · 只保留引号内的转录文本)

一、结果总览

1.1 CER 全景

非流式模型

一张图看清全局。三个关键发现

  1. Whisper-large-v3 与 faster-whisper-lv3 int8 在这四条语料上 CER 一致——demo_mixeddemo_mixed_noisy 上 CER 都是 0.000,demo_mixed_hard 上 CER 0.050,demo_mixed_conv 上 CER 0.200。int8 量化未观察到 CER 退化,但 wall time 从 1.05s 降到 0.78s。faster-whisper 作为常见 Whisper 生产部署方案的经验 · 在这四条合成中英混样本上得到部分复现。
  2. Whisper 家族参数量非单调影响精度base(74 M)在 demo_mixed_hard 上 CER 0.081 比 medium(769 M)的 0.087 还略低——说明在小样本上 · 参数量并不保证 CER 单调下降;解码行为、训练分布和样本内容都会影响结果。而 tiny → base → medium → large-v3 在 demo_mixed_noisy 上 CER 呈现 0.925 / 0.275 / 0.200 / 0.000 的清晰单调下降——在这 1 条 5 dB 合成白噪样本上 · Whisper 家族呈现更明显的容量相关趋势;是否泛化到真实噪声需另测
  3. 本篇选用的单语开源模型不适合中英混音频:Gen 3 三个 wav2vec 2.0 变体(英/英-Conformer/中)在四条语料上 CER 全部 > 0.68。这更多是“任务不匹配”而非“模型不行”——它们的 CTC 词表要么只有英文字母、要么只有中文汉字,没有跨语种解码能力。

为什么 FunASR CER 看上去偏高?——图上 FunASR Paraformer-zh(CER 0.23-0.55)/ SenseVoice-Small(CER 0.48-1.33)看上去比 Whisper-large-v3 差得多 · 这里的高 CER 不全是识别能力差 · 也有输出格式和归一化口径差异。三条具体原因:

  • 数字高度中文化:Paraformer-zh 训练分布倾向把阿拉伯数字还原成汉字(“25” → “二十五”、“13%” → “百分之十三”、“16” → “十六”)· 参考文本用阿拉伯数字 → 每个数字都算替换错误。
  • 英文专名 + 同音字Conformer transducer 被 Paraformer 输出成 conformer trin stucer(分词/拼写差异)· “演进” → “眼镜”、”Qwen2” → “酷 an 二” —— 这些在字符级 CER 里都算错。
  • SenseVoice 输出 4 个语义标签前缀<|zh|><|HAPPY|><|Speech|><|woitn|> —— 30+ 字符前缀全算插入错误。短语料 demo_mixed(60 字左右)的 CER 就被前缀占满(1.25)· 长语料 hard(170+ 字)相对占比小 · CER 就正常了(0.48)。

如果做统一后处理(数字统一 / 剥前缀标签 / 英文分词归一化)· FunASR 系列的 CER 会明显下降。但本文未把后处理后的分数纳入主图 · 保留了各家原始输出行为便于对比。

为什么 Qwen2-Audio CER 峰值那么高?——图上 Qwen2-Audio-7B 在 demo_mixed(2.15)/ demo_mixed_noisy(2.30)两条上 CER 远超 1.0 · 不是模型不行 · 是它把中文翻译成英文了

内容
REFHello world, 欢迎收听 ASR 五代演进, 25 年 WER 从 13% 降到 1.5%, thanks!
Qwen 剥 preamble 后 HYPhello world, welcome to listen asr five generations, twenty five years weer from thirteen percent to one point five percent. thanks.

“欢迎收听” → “welcome to listen”、”25 年” → “twenty five years” —— 大意接近但不是合格转录 · 主要错误是模型进入翻译模式 · 并伴随术语和数字表达漂移。字符级 CER 把每个汉字都算成”被替换为一串英文” · 分数就被拉到 2+。同一个 prompt(明确写了 "Keep the original mix of Chinese and English")在 demo_mixed_conv 上较好地保留中英混(剥前缀后 CER 0.25)· 在 demo_mixed_hard 上开头明显翻译但后半保留中英混(剥前缀后 CER 0.74)· 只有短句 demo_mixed / 加噪版 demo_mixed_noisy 上模型选择了翻译。Audio LLM 的行为跟音频内容分布强相关 · 单靠 prompt 不够 · 需要后处理语种检测或更强约束(详见后文 Gen 5 小节)。

流式模型(chunk feed)

流式实测三个代表模型(chunk-feed 送入 · 详见 § 二):

模型chunk 大小首字延迟平均 CER(4 语料)强项
Emformer-RNN-T (torchaudio)640 ms segment137-248 ms1.05(英文 checkpoint · 中英混不行)最低首字延迟
FunASR paraformer-zh-streaming600 ms chunk~615 ms0.42中英混 CER 最好
WeNet wenetspeech chunk500 ms Python API~1.04 s0.78中文纯语音较强

观察: - 首字延迟由 chunk 大小主导——Emformer 640 ms segment 拿到 137-248 ms · Paraformer 600 ms 拿到 615 ms(1 chunk)· WeNet 累积 wav 近似流式最慢(1.04 s)。 - 架构对(真流式)+ 训练数据对(中英混)= paraformer-streaming——是三者里唯一在本篇 4 条中英混上 CER 可接受(<0.60)的。 - 架构对 + 数据不对 = Emformer——首字延迟最快但 CER 高企(LibriSpeech-960h 英文 checkpoint 不适合中英混 · 面向中文/中英混训练的 streaming Transducer 或 Conformer-Transducer 系统才可能同时拿到低延迟和高精度)。

1.2 RTF 与显存

协议:RTF = 单条 demo_mixed 的推理 wall time / 音频时长 · 不含模型加载;本图排除云端 HTTP + 流式逐 chunk wall time

图上一眼观察:本篇实测的本地开源模型 RTF 均 < 0.1 · 单张 24 GB 消费级 GPU 上都远超实时。在这个单路短音频离线推理口径下 · 算力不是主要瓶颈;生产场景还要看并发、batch、队列、I/O 和流式调度。faster-whisper 显存追踪失真——CTranslate2 分配不走 PyTorch profiling · peak_mb=8 是假的 · 部署时仍需用 nvidia-smi 观测(实测约 3-4 GB)。

1.3 噪声鲁棒性

demo_mixed 加高斯白噪声到 SNR = 5 dB(本篇作为强白噪压力测试 · 不等价于真实地铁/咖啡厅——后者混杂 babble / 混响 / 人声干扰 · 需另测)。各模型表现分化非常清晰:

三个观察: 1. Whisper large 系列在本篇噪声语料上表现最稳——SNR = 5 dB 下 CER 零退化。可能与 Whisper 大规模弱监督训练覆盖了更多噪声/口音/场景有关;本篇只能证明这 1 条 5 dB 合成噪声样本上未退化。 2. Whisper-tiny 严重退化 4.3 倍(0.175 → 0.925)—— 端侧小模型对噪声高度敏感。做低算力部署时需要在噪声数据上验证,不能只用干净测试集。 3. Gen 2/3 单语模型 CER “反常降低”——不是变好了,是模型面对分布外音频直接输出短序列,插入错误反而变少。“CER 降低”未必等于“效果好” ——一定要看具体 hyp。

1.4 五代对照

本篇不是完整 benchmark · 而是用 4 条中英混合样本给五代路线放一个实测锚点:

代际本篇代表demo_mixed CER关键观察
Gen 1 · HMM/DNN-HMM未实测需要词典 / 声学模型 / 语言模型 / 解码图 · 复现成本高
Gen 2 · RNN-TEmformer-RNN-T2.025天然流式 · 但 LibriSpeech 英文 checkpoint 不适合中英混
Gen 3 · SSL/CTCwav2vec2 系列0.90-1.95极快 · 但本篇选用的单语 CTC head 跨语种能力弱
Gen 4 · Whisperlarge-v3 / faster-whisper0.000在这组样本上是最稳的纯转录基线
Gen 5 · Audio LLM / 云端 ASRQwen2-Audio / Seed-ASR 2.0 (openspeech)2.150 / 0.050CER 不是唯一指标 · 输出格式、任务能力、后处理更关键

三点结论

  1. 纯转录基线仍看 Whisper large-v3 / faster-whisper:在本篇 4 条中英混样本上 · large-v3 明显优于前代开源代表;faster-whisper 在 CER 不变的前提下缩短了 wall time。
  2. Gen 3 SSL 仍有速度价值:wav2vec2/CTC 路线 RTF 很低 · 适合单语、高吞吐、低资源场景;但本篇这些单语 checkpoint 不适合中英混。
  3. Gen 5 的重点不只是 CER:Qwen2-Audio 受 prompt 和输出格式影响;Seed-ASR 2.0 专用引擎(volc.seedasr.auc)在这 4 条上 CER 0.050 / 0.037 / 0.226 / 0.050、与 Whisper-large-v3 一档。评估这类系统时 · 需要同时看转录质量、格式稳定性、任务能力和端到端延迟。工业流式 ASR 常沿用 RNN-T / Transducer 类低延迟解码思路——本文的 Gen 2 Emformer-RNN-T checkpoint 只是这类结构的开源代表 · CER 崩不代表这类架构在生产上不行。

二、流式模型

本节测三类流式接口:Emformer 是 stateful streaming decoder(原生 · 每 segment 增量)· FunASR paraformer-streaming 是 chunk-attention 带 cache(原生 · 每 chunk 带 cache 前向)· WeNet 走 Python 高阶 API 累积 wav 每 chunk 重跑(模拟 · 不是 stateful runtime)· 三种测量口径不完全同类 · 首字延迟不宜直接横比。非流式模型见 § 三。

2.1 FunASR · paraformer-zh-streaming(真流式版)

FunASR 有专门的 paraformer-zh-streaming 变体(跟 § 3.5.1 里的非流式 paraformer-zh 是两个不同 checkpoint · encoder / decoder 都改造成 chunk-attention)· 用 chunk_size + look-back 参数控制上下文范围:

from funasr import AutoModel
m = AutoModel(model="paraformer-zh-streaming", disable_update=True)

cache = {}
chunk_stride = int(0.6 * 16000)   # 600 ms per chunk
for i in range(0, len(audio), chunk_stride):
    chunk = audio[i : i + chunk_stride]
    is_final = (i + chunk_stride >= len(audio))
    res = m.generate(input=chunk, cache=cache, is_final=is_final,
                     chunk_size=[0, 10, 5],
                     encoder_chunk_look_back=4,
                     decoder_chunk_look_back=1)
    partial = res[0]["text"]
    # 记录 partial 到达时刻

四条语料真流式实测

语料CER首字延迟转录(最终 hyp)
demo_mixed0.400618 mshelloworld欢迎收听AS二五代演进二十五年WE从百分之十三降到百分之一点五thanks
demo_mixed_hard0.36216 ms大家好今天讲formerance stucer的RTf优化我们把batchsize从十六提到六十四端到端延迟从三百二十毫秒降到一百八十毫秒a一百GPU上at十六精度WEr保持百分之二点七相比whisperge v三的五GVRAm我们的ter whisperint八只要三点二g thanksone
demo_mixed_conv0.296615 ms哎我跟你说啊昨天开会讨论gPT四o和cAS二的PKm说实话我觉得酷按二o也挺能打的anyway你nextweek有空吗我们约个oneon one聊聊ine time的事儿k就这么定了拜拜
demo_mixed_noisy0.600615 mshello问欢迎收听ASr五代眼镜二十五年WE二从百分之十三降到百分之一点五三

观察: - 首字延迟通常 ≈ 一个 chunk 就绪时间(600 ms · 用户端到端体验的下限 = 首个 chunk 采集 + 推理)· demo_mixed_hard 的 16 ms 是只算 compute-first-token latency(chunk 已送入到首字返回 · 不含首段采集等待)——首个 chunk 已经带完整开头进模型 · 推理耗时极短所以显得只有 16 ms。真实端到端体验仍需等首个 chunk 完整到达(600 ms)——首个 chunk 里就有清晰”大家好” · 立即出结果 · 后续 chunk 的推理耗时可以忽略在 chunk_stride 内。 - CER vs 非流式版:streaming CER 0.30-0.60 · 整段版 CER 0.24-0.55 —— streaming 版绝对 CER 增加 0.05-0.12(相对退化约 9-48%)(chunk 边界的少量遗漏 · 属正常代价)。 - noisy 上退化最大(0.60 vs 整段 0.55)· 噪声让 chunk 内识别更难。

2.2 WeNet · wenetspeech chunk 模拟(Python 高阶 API)

WeNet 官方的 wenetspeech checkpoint 支持 chunk 流式解码——本篇用 500 ms 一片累积送入的模式模拟(WeNet Python 高阶 API 只接受 wav path · 所以每 chunk 写临时 wav 再调 transcribe):

import wenet, soundfile as sf, tempfile, time
m = wenet.load_model("wenetspeech")

chunk_stride = int(0.5 * 16000)
partials = []
for i in range(0, len(audio), chunk_stride):
    acc = audio[: i + chunk_stride]      # 累积到目前的音频
    with tempfile.NamedTemporaryFile(suffix=".wav") as f:
        sf.write(f.name, acc, 16000)
        r = m.transcribe(f.name)
    partials.append(r.get("text", ""))

四条语料 chunk 模拟实测(chunk = 500 ms · 累积 wav + 每次重跑 · 非 stateful runtime · 不与原生 streaming 首字延迟直接比较):

语料CER首字延迟转录(最终 hyp)
demo_mixed0.9001.06s哈喽沃尔欢迎收听五代眼镜二十五年的比如一二从百分之十三降到百分之一点五克
demo_mixed_hard0.7561.04s大家好今天讲肯弗莫斯斯的T优化我们把斯从十六提到六十四端到端研持从三百二十毫秒降到一百八十毫秒A一百这批上伏的十六精度到比一二保持百分之二点七相比威斯特V三的五GV二AM我们的斯特威斯特印特八只要三点二GX瑞晚
demo_mixed_conv0.6171.04s唉我跟你说儿昨天开会讨论这P四和C的对KM说实话我觉得快二奥迪也挺能打的艾利薇你奈克斯有空吗我们约个弯安旺聊聊番痛的事儿好可就这么定了拜拜
demo_mixed_noisy0.8501.04s哈喽味欢迎收听未来五代演技二十五年到比零二从百分之十三降到百分之一点五三

观察: - CER 明显高于 paraformer-streaming(0.62-0.90 vs 0.30-0.60)—— WenetSpeech checkpoint 主要在中文纯语音上训练 · 对中英混不友好。 - 首字延迟 ~1.04s——比 paraformer-streaming 的 615 ms 慢约 400 ms。原因是本次实测走的是”累积 wav + 每 chunk 重推理”的近似流式路径 · 不是 WeNet C++/CN 的原生 stateful chunk-decoding。真正的 WeNet streaming 需要在 wenet_runtime 里跑 · 才能拿到官方公告的 <500 ms 首字延迟。 - 本篇 Python 高阶 API 更接近”chunk 模拟”而非”原生流式” —— WeNet 官方推荐生产走 C++ runtime 或 gRPC server。

2.3 Gen 2 · Emformer-RNN-T streaming (torchaudio · 段级 640 ms)

Emformer 是为流式设计的 Transformer 变体——用 decoder.infer(state, hypothesis) 保留 encoder state + 上一步 hypothesis · 每 segment(640 ms)增量解码:

from torchaudio.pipelines import EMFORMER_RNNT_BASE_LIBRISPEECH as bundle
sfx = bundle.get_streaming_feature_extractor()
dec = bundle.get_decoder()
tp  = bundle.get_token_processor()

state, hyp = None, None
seg_samples = bundle.segment_length * bundle.hop_length            # 640 ms
right_samples = bundle.right_context_length * bundle.hop_length    # 前瞻窗口
for i in range(0, len(audio), seg_samples):
    chunk = wav[i : i + seg_samples + right_samples]
    feats, lens = sfx(chunk)
    hyp, state = dec.infer(feats, lens, beam_width=10,
                            state=state, hypothesis=hyp)
    partial = tp(hyp[0][0])

四条语料真流式实测(segment_length=640 ms · beam=10):

语料CER首字延迟总 wall time转录(最终 hyp · 只英文能力)
demo_mixed1.575137 ms1.36shollow world wherein should he hear would i empty our shawl near wi the arts on beverages she said d...
demo_mixed_hard0.863165 ms5.96sthat is how since young can form a trans dusert artietie at yokoaess says she little kid alyosha's s...
demo_mixed_conv0.870220 ms4.37seh we'll get you sure so it can't help with how the g p sir as sarah the pique i am sure she will wi...
demo_mixed_noisy0.875248 ms1.74showever

观察: - compute-first-token latency 137-248 ms(chunk 已送入到首字返回的推理耗时)——但用户端到端首字延迟 ≈ 首段采集 640 ms + compute · 至少 ~800 ms。Emformer 快在 compute · 不是采集。 - CER 高企(0.86-1.58)——LibriSpeech-960h 英文 checkpoint · 训练分布里几乎没中英混。证明架构对(真流式)· 数据不对(单语训练)。 - noisy 上”however”就停——跟 § 3.1 整段跑一样 · 分布外音频 Emformer 直接放弃。

关键 tradeoff:Emformer 展示了“天然流式架构”的低延迟优势 —— 换成面向中文/中英混训练的 streaming Transducer 或 Conformer-Transducer 系统 · 才可能同时拿到低延迟和高精度。

三、非流式模型

本节全部走整段送入测试 · 记录 CER 和 wall time。注意:Emformer-RNN-T 架构原生支持流式(§ 2.3 有流式版对比)· 本节把它跟其它架构非流式模型一起放整段测试组 · 方便同口径对比 CER。

3.1 Gen 2 · Emformer-RNN-T · 整段送入(与 § 2.3 流式版对照)

本篇选用的 Gen 2 开源代表是 torchaudio 的 Emformer-RNN-T——Meta 2021 提出的流式友好 Transformer 变体,训练数据 LibriSpeech-960h 纯英文。

import torch, soundfile as sf
from torchaudio.pipelines import EMFORMER_RNNT_BASE_LIBRISPEECH as bundle

audio, sr = sf.read("demo_mixed.wav")           # 9.7s · 16k mono
wav = torch.from_numpy(audio.astype("float32"))

fe = bundle.get_feature_extractor()
dec = bundle.get_decoder()
tp = bundle.get_token_processor()

feats, _ = fe(wav)
feats = feats.unsqueeze(0)
lens = torch.tensor([feats.size(1)])
hyp = dec(feats, lens, beam_width=10)
print(tp(hyp[0][0]))
# → hollow world wherein should he hear would i empty our shorn yan wooi out on beverages she said down our beth and walk thanks
# CER=2.025 · RTF=0.079 · wall=0.77s · peak_mem≈0 MB (torchaudio 走 CPU-first 路径)

四条语料的转录结果(此模型只见过 LibriSpeech 英文 · 中英混直接崩):

语料CERRTF转录(关键片段)
demo_mixed2.0250.079hollow world wherein should he hear would i empty our shorn yan wooi ...
demo_mixed_hard1.4690.051that a heart since young can form a trans do sarda artietias ...
demo_mixed_conv1.2170.053eh we'll get you sure so i can't help with how the g p sir seepe sarah ...
demo_mixed_noisy0.8750.029how well(仅两个词 · 遇噪声直接放弃)

观察:噪声反而让 CER 降低——因为模型意识到“这不是 LibriSpeech 分布内数据”直接输出短序列,插入错误反而变少。这正是 Gen 2 单一数据源训练的脆弱性——一旦分布外,行为不可预测。

3.2 Gen 3 · wav2vec 2.0 系列

Gen 3 SSL 模型可以拿现成 CTC head 直接 inference,但本篇选用的可直接推理 CTC checkpoint 主要是单语微调版本——wav2vec2-large-960h-lv60-self 只见过英文,wav2vec2-xlsr53-chinese-zh-cn 只在中文上微调过。

from transformers import Wav2Vec2ForCTC, AutoProcessor
import torch, soundfile as sf

# 英文版本
name = "facebook/wav2vec2-large-960h-lv60-self"
proc = AutoProcessor.from_pretrained(name)
model = Wav2Vec2ForCTC.from_pretrained(name, use_safetensors=True).cuda().eval()

audio, sr = sf.read("demo_mixed.wav")
with torch.no_grad():
    inputs = proc(audio, sampling_rate=16000, return_tensors="pt").input_values.cuda()
    logits = model(inputs).logits
    pred_ids = torch.argmax(logits, dim=-1)
print(proc.batch_decode(pred_ids)[0])
# → HALLO WORLD WHY IN SHOED HIM SARWODIENSI ASONAN WE R TON BAVEN SHISON ...
# CER=1.450 · RTF=0.002 (wall=20ms) · peak_mem=1459 MB

三个 wav2vec2 变体在四条中英混语料上的表现(都靠不住 · 但快到极致):

变体(参数)demo_mixedhardconvnoisy
lv60-self · 英 · 300 M1.4500.9560.9651.150
conformer-rope · 英 · 618 M1.9501.3371.2701.900
xlsr53-chinese · 中 · 315 M0.9000.8870.6780.975

RTF 都在 0.002-0.003 · 显存 1.5-2.9 GB。

每条语料的典型输出片段wav2vec2-xlsr53-chinese · 三个变体中唯一在词表里带汉字的):

语料CER转录(前 60 字)
demo_mixed0.900海楼 沃 欢迎收 厅 黑埃塞尔 五 代 延近进二 十 五年到不 二 从百分之 十 三降到百分之一点五藩 子
demo_mixed_hard0.887大 家 好 今 天讲 肯 峰 木 C串 斯都 塞 的 而 梯亚 夫优话 我们 把 拜 C之 塞从十 六 提 到 六 十 四 端 道 D端 言持从三百二 十 好 <unk> 将降到 ...
demo_mixed_conv0.678艾 我 跟 你 昨 天 开会 讨 论之 劈 替 似 欧 和西 卑 埃 尔 的 辟 <unk> 们 说十 话我觉 得 库 二 凹 弟 也 挺 能 打 的 ...
demo_mixed_noisy0.975哈罗沃欢迎休梯威来尔五丹演字哈师五年在不一二总打分之学三向大百分军一典宇该子

观察:Gen 3 CTC 单语模型 RTF 都在 0.003 以下(xlsr53 在 demo_mixed 短样本上 wall time < 5 ms · 图上四舍五入到 0.000)——demo_mixed 单条口径粗算约数百倍实时(短样本 · 不代表批处理吞吐上限)。速度是 Whisper-large-v3 的 15 倍以上。代价是几乎不能跨语种——中英混内容里的 English 直接被强制解码成汉字或反过来。“快但认知面窄”是 Gen 3 SSL 的典型特征

3.3 Gen 4 · Whisper 家族

Whisper 是 Gen 4 的骨架旗舰。四个规格实测结果如下——整体上 large-v3 最稳;tiny/base/medium 之间并不严格单调 · 特别是 hard 上 base 略好于 medium

import whisper, torch
model = whisper.load_model("large-v3", device="cuda")     # 加载 ~5s · 3 GB fp16
result = model.transcribe("demo_mixed.wav", fp16=True)
print(result["text"])
# → Hello World,欢迎收听ASR五代演进25年,WER从13%降到1.5%Thanks
# CER=0.000 · RTF=0.048 · wall=0.47s · peak_mem=6399 MB

四档规格在四条语料上的完整对比

规格(参数)demo_mixedhardconvnoisy
whisper-tiny · 39 M0.1750.2060.4260.925
whisper-base · 74 M0.1750.0810.3130.275
whisper-medium · 769 M0.1250.0870.3390.200
whisper-large-v3 · 1.55 B0.0000.0500.2000.000

RTF (demo_mixed) 0.008-0.048 · peak_mem 204 MB - 6.4 GB · 参数越大越占显存但对噪声更稳。

每档的 demo_mixed 转录对比(同一条 9.7s 中英混音频):

模型转录
REFHello world, 欢迎收听 ASR 五代演进, 25 年 WER 从 13% 降到 1.5%, thanks!
tinyHello World 歡迎收聽ASR5代眼鏡25年WIR從13%降到1.5%Thanks(“演进”→“眼镜” · 繁体)
baseHello World 歡迎收聽AS25代眼鏡25年WER從13%降到1.5%Thanks(同 tiny + AS25 拼错)
mediumHello World 歡迎收聽ASR五代眼鏡25年WER從13%降到1.5%Thanks(“演进”→“眼镜” · 繁体)
large-v3Hello World,欢迎收听ASR五代演进25年,WER从13%降到1.5%Thanks(本篇归一化口径下 CER=0)

观察——在这条 demo_mixed 样本上,tiny/base/medium 都偏繁体或同音错字(“演进”→“眼镜”),只有 large-v3 输出简体并命中“演进”。tiny 和 base 的 CER 完全一致(0.175)· 这两档在这条样本上错误几乎相同。

3.4 Gen 4 加速 · faster-whisper 与 distil-whisper

3.4.1 faster-whisper · CTranslate2 int8

faster-whisper = openai/whisper 权重 + CTranslate2 推理引擎,做 int8 量化 + 推理内核优化。

from faster_whisper import WhisperModel
model = WhisperModel("large-v3", device="cuda", compute_type="int8_float16")
segments, _ = model.transcribe("demo_mixed.wav", beam_size=5)
text = "".join(s.text for s in segments)
# → Hello World,欢迎收听ASR五代演进25年,WER从13%降到1.5%Thanks
# CER=0.000 · wall=0.40s (vs 0.47s for openai/whisper large-v3)

faster-whisper 与官方 whisper-large-v3 逐条对比

语料官方 whisper-large-v3faster-whisper int8CER 差wall time 差
demo_mixedCER 0.000 / 0.47sCER 0.000 / 0.40s0-15%
demo_mixed_hardCER 0.050 / 1.05sCER 0.050 / 0.78s0-26%
demo_mixed_convCER 0.200 / 0.88sCER 0.200 / 0.63s0-28%
demo_mixed_noisyCER 0.000 / 0.41sCER 0.000 / 0.38s0-7%

结论在这 4 条样本上未观察到 CER 差异 · 平均 wall time 下降约 20% · VRAM 也降低peak_mem=8 MB 是 PyTorch memory tracker 未追踪 CTranslate2 的实际分配 · 真实 VRAM 用量 nvidia-smi 观测约为 3-4 GB)。faster-whisper 是 Whisper 生产部署常见选项之一

3.4.2 distil-whisper · 只留 2 层 decoder

distil-whisper large-v3 = large-v3 教师蒸馏出的 32→2 层 decoder 学生。参数量从 1.55 B 降到 756 M。取舍:主要面向英文 ASR 优化,本篇中英混样本上退化明显:

from transformers import pipeline
pipe = pipeline("automatic-speech-recognition",
                model="distil-whisper/distil-large-v3",
                device=0, torch_dtype=torch.float16, chunk_length_s=30)
result = pipe("demo_mixed.wav")
# → Hello World!    ← 只输出这几个字 就停了
# CER=0.750 · wall=0.12s

四条语料结果:

语料转录CER
demo_mixedHello World!0.750
demo_mixed_hardHello, today talk conformer transducer of RTF u-hawed. We put batch size from 16 to 64, d'd, d'd, d'n.E.0.G...0.650
demo_mixed_convHey, I'm going to say, two, I'll talk about GPT, 4O and C.A.S.R.2.E.S.R.D.R. Audio, e'n...0.835
demo_mixed_noisyHello World!0.750

结论distil-whisper 主要面向纯英文场景。中英混音频里它会把中文强解成英文单词 or 直接放弃。这是“英优先”定位的取舍 —— 蒸馏时选择保留哪些能力就丢掉哪些能力。

3.5 Gen 4 · FunASR 非流式(paraformer-zh / SenseVoice-Small)

FunASR(阿里达摩院)是 Gen 4 时代中文场景的另一支主线。两个代表模型:Paraformer-zh(非自回归 · 单遍解码 · 中文优先) · SenseVoice-Small(多语通用 · 带情感 + 事件标签)。

3.5.1 Paraformer-zh · 非自回归

from funasr import AutoModel
m = AutoModel(model="paraformer-zh", disable_update=True)
res = m.generate(input=audio, batch_size_s=300)
print(res[0]["text"])
# → 大 家 好 今 天 讲 conformer trin stucer 的 RTF 优 化 我 们 把 batch size 从 十 六 提 到 六 十 四 ...
# CER=0.244 · wall=0.18s (26.6s audio)

四条语料 Paraformer-zh 完整转录

语料CER转录
demo_mixed0.350hello world 欢 迎 收 听 ASR 五 代 演 进 二 十 五 年 WER 从 百 分 之 十 三 降 到 百 分 之 一 点 五 thanks
demo_mixed_hard0.244大 家 好 今 天 讲 conformer trin stucer 的 RTF 优 化 我 们 把 batch size 从 十 六 提 到 六 十 四 端 到 端 延 迟 从 三 百 二 十 毫 秒 降 到 一 百 八 十 毫 秒 a 一 百 GPU 上 float 十 六 精 度 WER 保 持 百 分 之 二 点 七 相 比 whisper large v 三 的 五 GVRA 我 们 的 faster whisper int 八 只 要 三 点 二 g thanks everyone
demo_mixed_conv0.235哎 我 跟 你 说 啊 昨 天 开 会 讨 论 GPT 四 o 和 CASR 的 PKM 说 实 话 我 觉 得 酷 an 二 audio 也 挺 能 打 的 anyway 你 next week 有 空 吗 我 们 约 个 one on one 聊 聊 fine time 的 事 ok 就 这 么 定 了 拜 拜
demo_mixed_noisy0.550hello world 欢 迎 收 听 ASR 五 代 眼 镜 二 十 五 年 WER 从 百 分 之 十 三 降 到 百 分 之 一 点 五 science

特点: - 数字高度中文化:“25 年” → “二 十 五 年”、“13%” → “百 分 之 十 三”、“2.7%” → “百 分 之 二 点 七”、“16” → “十 六” —— 参考文本用阿拉伯数字 · 每个数字都算替换错误 · 归一化前 CER 看起来”偏差大”但语义完整 - 中文场景强demo_mixed_conv(口语对话)CER 0.235 · 只比 whisper-large-v3 稍差 - 噪声鲁棒性偏弱demo_mixed_noisy CER 从 0.35 恶化到 0.55 · “演进”变“眼镜” · “thanks”变“science”

3.5.2 SenseVoice-Small · 多语 + 事件

m = AutoModel(model="iic/SenseVoiceSmall", disable_update=True)
res = m.generate(input=audio, batch_size_s=300)
# → <|zh|><|HAPPY|><|Speech|><|woitn|>hello world 欢迎收听 a s r 五代眼镜二十五年 ...

SenseVoice 会在 hyp 前输出 4 个语义标签<|zh|>(语言 zh)· <|HAPPY|>(情绪 · 训练数据的一个粗分类)· <|Speech|>(事件类型 · 音乐/说话/其它)· <|woitn|>(with-inverse-text-normalization · 反归一化)。

四条语料 SenseVoice-Small 完整结果(未剥离前缀标签的原始 CER):

语料CER前缀标签
demo_mixed1.250<\|zh\|><\|HAPPY\|><\|Speech\|><\|woitn\|>
demo_mixed_hard0.481同上
demo_mixed_conv0.591同上
demo_mixed_noisy1.325同上

这些标签在 CER 计算里算插入错误——demo_mixed/demo_mixed_noisy 都是短语料(9.7s · 参考文本才 60 字左右)· 30+ 字符的标签前缀直接把 CER 拉到 >1.0;而 demo_mixed_hard/demo_mixed_conv 参考文本更长(170-190 字符)· 标签的相对占比小、CER 也就 0.48-0.59。总览图里 SenseVoice 那条曲线包含标签开销——如果剥离标签只看后半段的文字 · 预计 CER 会明显下降(主因是标签插入不再计入)· 本文主图保留原始输出契约、未展示后处理 CER。这里保留原始 hyp 是为了展示 SenseVoice 的输出契约:它天生带更多“元信息”,不只是转录。

3.6 Gen 5 · Qwen2-Audio + arkcli + Seed-ASR HTTP

3.6.1 Qwen2-Audio-7B(开源本地)

Gen 5 Audio LLM 的输出行为跟前四代根本不同——它把转录当成一种指令,会自主决定是否附加解释

from transformers import Qwen2AudioForConditionalGeneration, AutoProcessor
torch.backends.cudnn.enabled = False   # 必要时关闭 cuDNN 以规避特定环境的初始化问题

audio, _ = librosa.load("demo_mixed.wav", sr=16000)     # 加载音频到 numpy · 采样率 16k
proc = AutoProcessor.from_pretrained("Qwen/Qwen2-Audio-7B-Instruct")
model = Qwen2AudioForConditionalGeneration.from_pretrained(
    "Qwen/Qwen2-Audio-7B-Instruct", torch_dtype=torch.float16, device_map="cuda"
).eval()

conversation = [{"role": "user", "content": [
    {"type": "audio", "audio_url": "demo_mixed.wav"},
    {"type": "text", "text": "Transcribe the audio into text. Keep the original mix of Chinese and English."}
]}]
text = proc.apply_chat_template(conversation, add_generation_prompt=True, tokenize=False)
inputs = proc(text=text, audio=[audio], sampling_rate=16000, return_tensors="pt", padding=True)
inputs = {k: v.to("cuda") for k, v in inputs.items()}
gen_ids = model.generate(**inputs, max_new_tokens=256, do_sample=False)

四条语料实测(CER 已按评测口径剥离 preamble;表格 cell 内是未做标点清洗的原始输出):

语料CER (剥离后)原始输出(前 200 字)
demo_mixed2.150The transcription of the audio is: 'hello world, welcome to listen asr five generations, twenty five years weer from thirteen percent to one point five percent. thanks.'
demo_mixed_hard0.744The complete transcription is: 'Hello everyone, today we're going to talk about the optimization of conformer transition dumper's RTF. We increased the batch size from 16 to 64,端到端延迟从320 milliseconds降到180 milliseconds, A100 GPU 上 float16精度WER保持百分之二点七。...'
demo_mixed_conv0.252The complete transcription, mixing Chinese and English, is: '哎,我跟你说啊,昨天开会讨论GPT4O和CSR的PKM。说实话,我觉得KuaianAudio也挺能打的。Anyway,你next week有空吗?我们约个one on one聊聊Fintech的事儿,OK就这么定了,拜拜。'
demo_mixed_noisy2.300The transcription is: 'hello work, welcome to listen asr five generation progress. twenty five years, war from thirteen percent to one point five percent. thanks.'

两个观察: 1. demo_mixed_conv 剥离后 CER 0.252 · 跟 whisper-medium 相当——只在这条语料上把中英原样保留了。 2. demo_mixed/demo_mixed_hard/demo_mixed_noisy 剥离后 CER 仍 > 0.7——四条语料用同一个 prompt"Transcribe the audio into text. Keep the original mix of Chinese and English.")· 但模型仍把中文强翻译为英文(”欢迎收听” → “welcome to listen”·”演进” → “generations”)。Audio LLM 即使加了明确指令、也可能因音频内容分布不同而回退到”翻译”模式——单纯 prompt 工程不够、需要更强约束(system prompt + few-shot 示例)或后处理语种检测。

结论:Gen 5 的输出行为高度依赖 prompt 工程 + 后处理。它可以做的事情远超转录(翻译、情绪、说话人、摘要),但也意味着没有强约束时输出格式不稳定“用 Whisper 做纯 ASR,用 Qwen2-Audio 做多任务音频理解”是当前最合理的分工

3.6.2 火山 arkcli 通用入口(audio LLM 路径)

这条走的是通用多模态 audio LLM · 不是权重专用 ASR——arkcli 的 +understand asr sub-skill 会自动路由到 doubao-seed-2-0-lite-260428(Doubao Seed 2.0 lite 通用 audio LLM · 类似 Qwen2-Audio 但闭源)。

arkcli +understand asr --input @demo_mixed.wav
# → hello world 欢迎收听 asr 五代眼镜 二十五年 wer 从百分之十三降到百分之一点五 thanks

四条语料实测(每条独立 HTTP 请求、含网络往返 · 与本地 GPU 结果不可直接比 wall time):

语料CERwall time转录(关键片段)
demo_mixed0.40014.2shello world 欢迎收听 asr 五代眼镜 二十五年 wer 从百分之十三降到百分之一点五 thanks
demo_mixed_hard0.19410.4s大家好今天讲Conformer Transducer的RTF优化我们把batch size从十六提到六十四端到端延迟从三百二十毫秒降到一百八十毫秒A100 GPU上float十六精度WER保持百分之二点七...
demo_mixed_conv0.19132.1s哎我跟你说儿昨天开会讨论gpt4o和cas2的pk说实话我觉得qwen2 audio也挺能打的anyway你next week有空吗我们约个one on one聊聊finetune的事儿ok就这么定了拜拜
demo_mixed_noisy0.3258.6shello world 欢迎收听 asr 五代眼镜 25年 wer从百分之十三降到百分之一点五 thanks

特点: - 数字高度中文化(“25” → “二十五”、“13%” → “百分之十三”)· 在这次 arkcli 路径的输出中表现为数字中文化偏好 · CER 里算替换错误 · 但语义完整。 - “演进”→“眼镜” 是同发音混淆——Whisper-tiny/base/medium 在这条语料上也犯同样错(前面 Whisper 家族的“每档 demo_mixed 转录对比”表可看出)· 可能与 edge-tts 合成音的发音特征和同音词竞争有关;多个模型出现该错 · 但 large-v3 / Paraformer 未踩。 - wall time 数十秒 远高于本地 GPU · 但不含 GPU 部署成本 + 支持 diarization / SRT 对齐 / meeting-minutes 等指令切换——见 part 6 中 Seed-ASR 小节的完整 sub-skill 列表。

3.6.3 Seed-ASR 2.0 专用引擎(openspeech 直连)

这条才是权重专用 ASR 引擎——绕开 arkcli · 直接调 openspeech HTTP API · Resource ID volc.seedasr.auc。用 X-Api-Key 认证 · submit + query 两步异步(提交返回 task_id · 轮询查询)· 音频需要放在可公网访问的 URL(对象存储 / 静态 hosting 都行)。

import requests, uuid, time
API_KEY = "<your-api-key-from-volc-console>"
BASE = "https://openspeech.bytedance.com/api/v3/auc/bigmodel"

def transcribe(audio_url):
    task_id = str(uuid.uuid4())
    r = requests.post(f"{BASE}/submit", headers={
        "X-Api-Key": API_KEY,
        "X-Api-Resource-Id": "volc.seedasr.auc",
        "X-Api-Request-Id": task_id,
        "X-Api-Sequence": "-1",
    }, json={
        "user": {"uid": "part7"},
        "audio": {"format": "wav", "url": audio_url},
        "request": {"model_name": "bigmodel", "enable_itn": True, "enable_punc": True},
    })
    assert r.headers["X-Api-Status-Code"] == "20000000", r.text
    # poll query · 最大 60 次 · 60s deadline
    for _ in range(60):
        time.sleep(1.0)
        q = requests.post(f"{BASE}/query", headers={
            "X-Api-Key": API_KEY, "X-Api-Resource-Id": "volc.seedasr.auc",
            "X-Api-Request-Id": task_id,
        }, json={})   # 注意 query 必须发 json={} · 否则报 "unexpected end of JSON input"
        code = q.headers["X-Api-Status-Code"]
        if code == "20000000": return q.json()["result"]["text"]
        elif code == "20000001": continue      # in progress
        else: raise RuntimeError(f"code={code} msg={q.headers.get('X-Api-Status-Message')} body={q.text}")
    raise TimeoutError("query polling exceeded 60s deadline")

四条语料实测volc.seedasr.auc · 2.0 专用引擎 · openspeech HTTP · 与本地 GPU 不可直接比 wall time):

语料CERwall time转录(关键片段)
demo_mixed0.0503.05sHello World 欢迎收听 ASR 五代眼镜。25年, WER 从13%降到1.5%。Thanks
demo_mixed_hard0.0373.65s大家好,今天讲 Conformer Transducer 的 RTF 优化。我们把 Batch Size 从16提到64,端到端延迟从320毫秒降到180毫秒。 A100 GPU 上 float 16精度,WER 保持2.7%。相比 Whisper Large V3的5G VRAM,我们的 faster whisper int 8只要3.2G。 Thanks everyone
demo_mixed_conv0.2263.08s哎,我跟你说啊,昨天开会讨论 GPT 4O 和 C ASR 的 PK,M 说实话我觉得昆2 Audio 也挺能打的。 Anyway 你 next week 有空吗?我们约个 one on one 聊聊 Fantune 的事,OK?就这么定了,拜拜!
demo_mixed_noisy0.0501.72sHello World 欢迎收听 ASR 五代眼镜。25年,WER 从13%降到1.5%。Thanks

特点: - CER 明显好于 arkcli 路径——干净语料 0.05(与 whisper-large-v3 一档 · 只差在“演进”→“眼镜”这个 TTS 合成音的同发音字)· 长口语对话 0.23(跟 arkcli 路径持平)。 - 保留原始阿拉伯数字(“25年”、“13%”、“2.7%”、“320毫秒”)· 不像 arkcli audio LLM 路径那样中文化——这是专用 ASR 引擎的规范化行为。 - wall time 1.7-3.7s · 显著低于 arkcli 路径的 8-32s(后者是 audio LLM · 走大模型生成 · 慢得多)。

作为对照 · 同批也跑了 volc.bigasr.auc(Doubao-录音文件识别 · 标准 1.0)· 4 条 CER 与 2.0 几乎一致(0.050 / 0.037 / 0.209 / 0.050)· 因与 Seed-ASR 2.0 曲线几乎重合 · 主图只保留 2.0 · 不单列一行

四、写在最后:ASR 并入多模态入口

从 1960 年代的 IBM Shoebox 到今天的 Audio LLM,ASR 前四代主要在回答一个问题:如何更准地把声音转成文字。Gen 5 开始,这个问题被抬高到:如何让机器理解声音里的语义、上下文和交互意图

本篇实测给出的结论很清楚:Whisper-large-v3 / faster-whisper 仍是纯转录基线;Qwen2-Audio 这类 Audio LLM 更像“通用助手在处理音频任务”,输出可能带 preamble、翻译或摘要;Seed-ASR 代表专用云端 ASR 引擎 · 适合批处理 / 文件识别;GPT-4o Realtime 代表实时全双工语音交互入口。二者都说明 ASR 正在并入更大的语音 / 多模态系统 · 但延迟模型和产品形态不同。

所以,ASR 不会消失,但它作为独立产品入口会变少。字幕生产、语音质检、会议纪要、低成本批处理仍然需要专用 ASR;而面向用户的语音入口,会越来越多地并入 audio / multimodal LLM。评测也要跟着变:WER / CER 仍有价值,但已经不能单独解释 preamble、摘要、情绪、说话人和结构化输出这些 Gen 5 行为。

这就是五代演进的终点判断:ASR 从“独立模型”走向“多模态系统里的基础能力”。底层转录仍然重要,只是它越来越少单独站在产品最前台。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_34941290/article/details/163862979

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--