一、什么是 MOS:ITU-T P.800
MOS 本身不是算法 ,是 ITU-T P.800 定义的主观听测方法------找 20+ 名听者,戴规定听音设备,在指定房间里对同一段语音按 1--5 分打分(ACR,Absolute Category Rating),取平均即为 MOS 值。所有后面要讲的"客观 MOS 算法"都是在拟合这个主观打分。
| MOS | 感知质量 | 典型体验 |
|---|---|---|
| 4.5--5.0 | Excellent | 接近真人,失真极少 |
| 4.0--4.4 | Good | 清晰可靠,小瑕疵不可察 |
| 3.5--3.9 | Fair | 可懂,但能感到压缩/噪声 |
| 3.0--3.4 | Poor | 仍能通话,但影响舒适度 |
| < 3.0 | Bad | 严重失真/中断 |
企业语音一般把 MOS ≥ 4.0 当合格线,< 3.5 用户就开始抱怨。一次完整 P.800 听测要 20+ 人 × 每人 2 小时 × 每小时 200--500 元劳务,五位数起步,2--4 周出结果------业务闭环里没法用,这也是后面所有客观 MOS 算法存在的根本理由。
二、为什么必须要客观 MOS
主观 MOS 最准,但慢、贵、不能实时;业务闭环里没法用。整支客观 MOS 技术树,本质是在解一件事------怎么把 P.800 的输出压缩到分钟级、能跑线上音频。
2.1 ANS/AEC 的效果,是一个主观问题
回到问题的物理层:
- ANS (噪声抑制)要做的是「把背景噪声压掉,把人声留下」。信号层可以算 SNR 提升,但用户体验的关键不是 SNR------压完之后人声是不是还自然才是核心。DNN ANS 经常出现 SNR 涨 8 dB、主观质量反而下降的情况,因为压噪的同时把语音的谐波和辅音也削掉了。
- AEC (回声消除)要做的是「远端参考信号在近端麦克风里的回声成分」削掉,同时保住近端说话人。信号层可以算 ERLE(Echo Return Loss Enhancement) 和残留回声能量,但工业界真正关心的是双讲(Double-Talk)场景------两边同时说话时近端语音有没有被误消掉。这个"误消"用信号指标很难量化,人耳一听就知道。
信号级指标(SNR / ERLE / SI-SDR)能证明算法在做事,但证明不了做得让人满意。用户满意度天然是主观的,最终仲裁标准只能是人耳听感------也就是 MOS。
2.2 主观 MOS 撑不起训练闭环
DNN 一天能跑 3--5 版模型,一次 P.800 主观听测却要 2--4 周、五位数成本;不同批次听者还有 ±0.3 的打分噪声,"这版比上版好 0.1"根本比不出。更别说线上真实用户音频(最能反映模型真实表现)根本不能拉去听测。
评估比训练慢 100 倍,闭环直接断掉 。这就是为什么从 2001 年 PESQ 开始,业界一直在同一条路上走------用算法拟合 P.800 的输出,让 ANS/AEC 评估能在分钟级完成、能跑在线上真实音频上、能覆盖百万级样本。
2.3 客观 MOS 算法与周边指标全景
客观 MOS 算法分五代,另外还有三个有参指标(STOI/SI-SDR/ViSQOL)不预测 MOS 但常和 MOS 一起出现在评估表里。一次性摆清所有指标的属性和边界:
| 代际 | 算法 | 类别 | 有参 | 测什么 | 典型用途 | 关键局限 |
|---|---|---|---|---|---|---|
| --- | STOI / ESTOI | 可懂度 | 是 | 词能不能听出来 | ASR 前处理、极低 SNR、AEC 语音保留下限 | 对加性噪声/回声不敏感 |
| --- | SI-SDR / SI-SNR | 信号失真 | 是 | 波形跟 clean 差多少 dB | DNN 训练 loss、源分离评估 | 涨了不代表主观质量提升 |
| 1 | PESQ (2001) | 感知质量 | 是 | 主观好听度(老一代) | 论文兼容、窄带电话 | DNN artifact 预测差、低分段不准 |
| 1 | POLQA (2011) | 感知质量 | 是 | 主观好听度(SOTA 有参) | 运营商合规测试 | 闭源商用,10-50 万美元授权 |
| --- | ViSQOL v3 (2020) | 感知质量 | 是 | 主观好听度(POLQA 类) | 编解码器评估、开源替代 POLQA | 对语音失真不如 POLQA 灵敏 |
| 2 | P.563 (2004) | 感知质量 | 否 | 主观好听度(规则映射) | 已退出主流 | 精度不够,PCC ~0.7 |
| 2 | E-Model (G.107, 1998) | 网络质量 | 否 | 从网络参数推 MOS | VoIP/SIP 网络侧监控 | 不看音频,对 AI 失真无感 |
| 3 | DNSMOS (2020) | 感知质量 | 否 | 主观好听度(SIG/BAK/OVRL 三分诊断) | ANS 迭代、DNS Challenge 官方指标 | 微软权重"研究许可",商用有风险;对编码失真反向偏置 |
| 3 | DNSMOS Pro (2024) | 感知质量 | 否 | 三分 + 高斯后验(不确定度) | VoIP 端侧、生产环境替代原版 | 训练分布仍偏 ANS |
| 3 | NISQA (2021) | 感知质量 | 否 | 主观好听度(MOS + 4 维诊断) | VoIP / TTS 评估、诊断维度定位问题 | 训练在众包 P.808 上,OOD 泛化受限 |
| 3 | MOSNet (2019) | 感知质量 | 否 | 主观好听度(TF1 老代码) | 学术复现基线 | 精度已被 SSL 系全面超越 |
| 4 | SSL-MOS (2022) | 感知质量 | 否 | 主观好听度 | 学术 baseline | 精度弱于 UTMOS 系 |
| 4 | UTMOS (2022) | 感知质量 | 否 | 主观好听度(TTS/VC 域) | TTS/VC 评估 | 跨域打分不可信 |
| 4 | UTMOSv2 (2024) | 感知质量 | 否 | 主观好听度(跨域鲁棒) | TTS/VC/codec baseline | 歌唱等新品类仍崩 |
| 4 | HighRateMOS (2025) | 感知质量 | 否 | 主观好听度(48 kHz 感知) | HD Voice 评估 | 代码未完全开源 |
| 5 | SpeechQualityLLM (2025) | 感知质量 + 解释 | 否 | 数值 + 文本诊断 | 少批量高价值评审报告 | 推理成本高,比 UTMOSv2 慢 10-50 倍 |
| 5 | PS-SQA (2024) | 感知质量 | 否 | 歌唱 MOS | 歌唱评估垂类 | 训练数据小、通用性差 |
一句话读表 :有参档在实验室内是硬通货 (PESQ/POLQA/ViSQOL);无参 DNN 系是工业界主流 (DNSMOS/NISQA/UTMOSv2);LLM 系是可解释性的答案,但推理成本挡在生产之外。
这一整支技术树的第一性原理,不是预测得多准,是 多快能让算法工程师拿到反馈------精度可以退让,闭环速度不能退让。所以 DNSMOS 只有几 MB、UTMOSv2 都能在 CPU 跑,而 SpeechQualityLLM 这种 7B 模型至今只用在离线评测报告,不进 CI/CD。
三、五代打分器实测
有了这五代客观打分器,但它们并不总是给出一致的答案。做 ANS/AEC 训练评估时,有件事很典型:同一段处理后的语音,不同打分器给出的分完全打不齐 。这不是模型坏了,是范式差异。跑一组实测看看:
样本:一段 8 秒 48 kHz 单声道中文语音,两组共 9 段。TTS 组合成文本 "仓库的后面是一间小屋,太阳从东方升起来。"
| 组别 | 样本 | 说明 |
|---|---|---|
| ANS/AEC | 参考信号 | 干净人声,PESQ 的 clean ref |
| ANS/AEC | 处理前样本 | 叠加背景噪声 + 回声后的近端麦克风信号 |
| ANS/AEC | 算法处理 1 | 过度抑制------噪声压干净但谐波受损,有"喘气感" |
| ANS/AEC | 算法处理 2 | 中等强度------噪声适中,语音基本完整 |
| ANS/AEC | 算法处理 3 | 保守------保语音,噪声压得不狠,最接近参考 |
| TTS | Edge Xiaoxiao | 微软 Edge Neural TTS,zh-CN-XiaoxiaoNeural 女声 |
| TTS | Edge Yunxi | 微软 Edge Neural TTS,zh-CN-YunxiNeural 男声 |
| TTS | gTTS | Google Translate 后端,老一代,偏机械 |
| TTS | 电话带压缩版 gTTS | 300-3400 Hz 滤波 + 动态压缩 + μ-law,"客服热线音质" |
ANS/AEC 组三个算法抑制强度梯度递减,看打分器对"过压 vs 欠压"的敏感度差异;TTS 组三个正常 + 一个故意劣化,看打分器对编码链路失真的辨识。
打分器 :本次实测跑了 13 个开源单点打分器 ------第 1-5 代 MOS 系(PESQ / DNSMOS SIG/BAK/OVRL / DNSMOS Pro / NISQA / UTMOS / UTMOSv2 / SQUIM-SUB)+ 周边有参指标(STOI / SI-SDR)+ TTS 场景常用(Audiobox AE 四维 / SIM / Whisper CER)。POLQA(第 1 代闭源)和 SpeechQualityLLM(第 5 代权重待放)未参评。PESQ 需要参考信号,TTS 组没有对应参考,用 / 表示不适用;CER 只对 TTS 组(有 ground-truth 文本)。

图分两幅------上面是 9 个 MOS 尺度打分器(1-5),下面是 Audiobox AE(1-10)/ SIM(0-1)/ CER(0-1)三种异构尺度。图里能读出六个结论:
- 绝对分不可比 。同一个"算法处理 3":PESQ 2.34、DNSMOS OVRL 3.20、DNSMOS Pro 4.29、NISQA 3.78、UTMOS 2.23、UTMOSv2 2.18、SQUIM-MOS 4.49------七个数各自在自己刻度里都合理,但跨打分器直接比数值没有意义。选一个盯一个,别混着看。
- UTMOS 训练在 TTS 域,用在 ANS/AEC 输出上系统性偏低(对比 ANS 算法 3 和 TTS Edge Xiaoxiao:DNSMOS OVRL 都 ~3.2,UTMOS 分别是 2.23 和 3.83;UTMOSv2 略修正了偏差但没完全消除,两个场景是 2.18 vs 3.04)。
- UTMOSv2 反常低估干净人声 :参考信号(干净真人录音)UTMOSv2 只给 3.04,明显低于 DNSMOS Pro 4.32、NISQA 4.76、SQUIM-MOS 4.47------真人录音对 UTMOSv2 反而是"域外"(它训练在合成语音上),这个方向的域偏差在打 TTS 时看不到,但在打真人录音时暴露无遗。
- DNSMOS 对"限带 + 编码压缩"失真不敏感 :电话带压缩版 gTTS 的原版 DNSMOS SIG 竟然比原 gTTS 还高 0.02(3.61 vs 3.59);DNSMOS Pro 在这一项掉到 3.24(低于原 gTTS 的 4.28),说明 Pro 版训练分布对压缩失真更敏感------同一家族不同版本,行为可以差很多。
- NISQA 对 TTS 特别宽容:三个正常 TTS 样本 NISQA 都给到 4.7--4.9,明显高于其它无参打分器(DNSMOS OVRL 只有 3.2--3.4);这跟 NISQA 训练数据里 TTS 样本多相关。劣化 gTTS 直接砸到 2.68,区分度也很强。
- Audiobox AE 更看"录音质感"而非"内容真实" :Audiobox PQ(制作质感)在四个 TTS 样本上 7.12-7.95,反而比真人参考信号的 7.51 更高------Audiobox 更看清晰、频响平衡这些"制作层"特征,现代 TTS 的干净输出在它眼里能超过原始麦克风录音。用它评 TTS 产品的"听感质量"很合适,但不能替代 MOS 判断"像不像真人"。
STOI / SI-SDR / SIM 的辅助数字 (ANS/AEC 组):算法处理 1/2/3 的 STOI 从 0.77→0.87→0.91 逐档上升,SI-SDR 从 +5.08 dB→+9.02 dB→+9.96 dB,SIM 从 0.60→0.61→0.89 也一路走高------三个有参/半有参指标跟"算法强度递减"完全吻合,说明信号级质量的排序 相对稳定;分歧主要在无参 DNN 系的感知打分 上。SIM 的处理前样本给到 0.37 值得注意------背景噪声大到能扰乱说话人识别的 embedding,这是"噪声不仅伤听感,还伤下游任务"的直接证据。
一句话:没有单一 MOS 打分器覆盖所有场景,选打分器前先看你的失真类型和它训练分布是不是对上。下面按代际展开每一代的原理、开源状态和踩坑。
两次结构性转折:
- 转折一(第 1→3 代):有参 → 无参。POLQA 到现在仍是有参这一档里精度最高的,但真实业务场景越来越拿不到 clean reference------线上电话录音、DNN 降噪输出、TTS 合成语音都没有"标准答案"可对齐,逼出无参 DNN。
- 转折二(第 4→5 代):单点数值 → 描述式评估。业务需要「哪里差、差几分、为什么差」,逼出 Audio-LLM 生成文本诊断。
四、第 1 代:PESQ / POLQA------有参考的感知域度量
有参考(intrusive)是这一代的共同前提:算法需要同时拿到 clean reference 和 degraded 版本才能打分。实验室调试和自建评测集时依然好用------PESQ 至今是学术论文的通用 baseline,POLQA 更是运营商合规测试的事实基准。真正的局限有两个:线上质量监控拿不到 clean ref ;POLQA 收费闭源,不易集成到业务链路。
4.1 PESQ (ITU-T P.862, 2001)
窄带电话时代的事实标准,输入 ref(干净参考) + deg(劣化后)时间对齐两条音频,经 Bark 域感知模型算对称/非对称扰动,线性映射到 MOS-LQO (1--5)。
关键洞察在两处:Bark 域 拟合耳蜗对不同频率的分辨率不均等;非对称扰动让"加入新噪声"比"丢失原信号"惩罚更重------符合人耳"新噪音更烦"的直觉。
参考实现 C 代码开源(ITU 官网可下 P.862 附录,ITU 文档本身收 CHF ~300 但代码免费),Python 走 pesq 库:
python
# pip install pesq soundfile librosa
from pesq import pesq
import soundfile as sf, librosa, numpy as np
def load_16k(p):
w, sr = sf.read(p)
if w.ndim > 1: w = w.mean(1)
if sr != 16000:
w = librosa.resample(w.astype(np.float32), orig_sr=sr, target_sr=16000)
return w.astype(np.float32)
ref = load_16k('wav/参考信号.wav')
deg = load_16k('wav/算法处理3.wav')
n = min(len(ref), len(deg))
# 'wb' = wideband (16 kHz, 50--7000 Hz), 'nb' = narrowband (8 kHz)
score = pesq(16000, ref[:n], deg[:n], 'wb')
print(f'PESQ-WB MOS-LQO: {score:.4f}')
# PESQ-WB MOS-LQO: 2.3419
客观缺陷 :PESQ 的失真模型停留在 2001 年的手工感知特征,两个已知问题在现代 DNN 场景下会暴露------(1) 对 DNN 非线性 artifact(金属声、机器味)预测不准,PESQ 分和主观 MOS 会背离;(2) MOS < 3 区间与主观相关性只有 0.6-0.7,高分段能到 0.9。做 DNN 降噪或 AEC 迭代时,PESQ 至少要叠一个 DNSMOS 或 NISQA 交叉验证。
4.2 POLQA (ITU-T P.863, 2011 / v3 2018)
PESQ 的官方继任者,也是当前运营商世界的合规基准。相比 PESQ 三处结构性改动:频带扩到 50--14000 Hz (超宽带,覆盖 HD Voice / VoLTE / 5G VoNR)、听觉模型加入时域/频域掩蔽和响度整合 、从头按 MOS-LQO 设计 (PESQ 是 PSQM 打补丁)。全分段与主观相关性都能到 0.9+,对 AGC、EC、AMR-WB、VoIP 抖动更鲁棒。
闭源商用 ,OPTICOM 独家代理:加密狗 + NDA、单次开发授权 10-50 万美元量级,学术可申请免费 NDA 版(只给可执行)。没有官方 Python 绑定 ,工程上用 subprocess 调 OPTICOM/R&S/Spirent 提供的可执行:
python
# 伪代码:调用 OPTICOM POLQA 可执行
import subprocess
result = subprocess.run(
['polqa', '-r', 'clean.wav', '-d', 'degraded.wav', '-m', 'swb'],
capture_output=True, text=True
)
# 解析 stdout 拿 MOS-LQO
不做运营商集采、不需要"P.863 合规章"的测试报告时,POLQA 的钱可以省------2025 年 UTMOSv2 + DNSMOS Pro 在大多数 TTS/降噪场景已能给到运营商级鉴别力。POLQA 唯一不可替代的是「有权威机构盖章」这个信任层。
五、周边指标:STOI / SI-SDR / ViSQOL
有三个指标不预测 MOS 但和 MOS 一起出现在几乎所有 ANS/AEC/源分离论文里。三个都是有参考指标------都需要 clean + degraded 配对,跟第 1 代 PESQ/POLQA 同类。搞清它们跟 MOS 打分器的分工,评估表才不会混着用。
5.1 STOI (Short-Time Objective Intelligibility, 2010)
测什么 :可懂度 (intelligibility)------听者能听出多少百分比的词。只测能不能听清,不测好不好听。
原理 :clean 和 degraded 都做 STFT → 分 1/3 倍频程 → 15 帧短时窗内计算包络相关系数 → 平均。核心洞察是:词的辨识主要靠包络起伏而不是频谱细节,所以只要包络对齐好,即使有背景噪声也能听懂。
输出:0--1(论文常乘 100 变百分比)。典型值:
- clean vs clean = 1.0
- SNR 0 dB 混音 ~0.7
- SNR -5 dB 掉到 0.5 以下(人耳基本听不清)
开源与用法 :MIT 开源,Python 走 pystoi:
python
# pip install pystoi
from pystoi import stoi
import soundfile as sf
clean, sr = sf.read('wav/参考信号.wav')
deg, _ = sf.read('wav/算法处理3.wav')
n = min(len(clean), len(deg))
score = stoi(clean[:n], deg[:n], sr, extended=False) # extended=True 用 ESTOI (2016)
print(f'STOI: {score:.4f}')
# STOI: 0.9088
敏感 / 不敏感的方向不对称 (AEC/ANS 场景要特别注意):STOI 对语音本身的削弱 敏感,对加性失真不敏感。
- 敏感:AEC 抑制过强、把近端语音压掉一部分 → 包络失真 → STOI 明显下降
- 不敏感:AEC 残留回声、ANS 残留噪声------只要没盖过语音包络,STOI 几乎不变;同理金属声、机器味这类频谱失真 STOI 也察觉不到
所以 STOI 适合作为语音保留维度的下限指标------如果 STOI 掉了,一定是伤到语音本身了;但 STOI 不掉,不代表输出干净好听。
5.2 SI-SDR (Scale-Invariant Signal-to-Distortion Ratio, 2019)
测什么 :信号级失真 dB 数------分离/降噪后的语音波形跟 clean 差多少。
原理 :把估计信号 s_hat 投影到 clean s 上得到"信号成分",剩下的算失真。SI-SDR = 10 * log10(|s_target|^2 / |e_res|^2)。scale-invariant 是关键------它先把 s_hat 缩到跟 s 匹配的能量,避免"整体音量偏一点就掉分"。
输出:dB,越高越好。好模型能到 15+ dB,20 dB 以上基本听不出差别。
开源与用法:所有主流包都有,torchmetrics 最方便:
python
# pip install torchmetrics soundfile
import torch, soundfile as sf
from torchmetrics.audio import ScaleInvariantSignalDistortionRatio
clean, _ = sf.read('wav/参考信号.wav')
deg, _ = sf.read('wav/算法处理3.wav')
n = min(len(clean), len(deg))
metric = ScaleInvariantSignalDistortionRatio()
score = metric(torch.tensor(deg[:n]), torch.tensor(clean[:n])) # 单位: dB
print(f'SI-SDR: {score.item():.4f} dB')
# SI-SDR: 9.9955 dB
关键差别 :SI-SDR 在 ANS/源分离训练里当 loss 用得比当评估指标多------它可导,DNSMOS/UTMOS 都不可导。ConvTasNet / DPRNN / DPT-Net 那批经典源分离模型全部拿 SI-SDR 或它的变种 SI-SNR 当训练目标。
5.3 ViSQOL v3 (Google, 2020)
测什么 :跟 POLQA 同类的感知质量 ------但Apache 2.0 开源。可以理解成"穷人版 POLQA",不用花五位数买授权。
原理:ref/deg 都做 gammatone 频谱图 → NSIM (Neurogram Similarity Index Measure) 相似度 → 映射到 MOS-LQO。支持 8-48 kHz,语音+音乐都能评。
开源与用法:Google 官方 C++ 实现 + Python 绑定:
python
# pip install visqol (Linux/Mac; Windows 走 bazel build)
from visqol import visqol_lib_py
from visqol.pb2 import visqol_config_pb2, similarity_result_pb2
config = visqol_config_pb2.VisqolConfig()
config.audio.sample_rate = 48000
config.options.svr_model_path = "libsvm_nu_svr_model.txt" # 官方 release 里有
api = visqol_lib_py.VisqolApi()
api.Create(config)
result = api.Measure(ref_np, deg_np)
print(result.moslqo)
典型场景 :编解码器评估 (Opus/EVS/Lyra 输出)------ViSQOL 就是 Google 为评自家 codec 做的。开源音频圈默认选它当 POLQA 替代。
常见陷阱 :SI-SDR 涨了但 DNSMOS 反而降------这在过拟合训练集分布时经常出现。模型学会了"把噪声段和语音段的波形对齐得跟 clean 极像",SI-SDR 冲高,但引入了新的谱失真,人耳听着更难受。别只盯 SI-SDR 训练,配 DNSMOS 或 NISQA 做感知维度交叉验证是标准做法。
六、第 2 代:P.563 / E-Model------无参考的第一次尝试
2000 年代初业界就意识到有参用不了线上音频,做过两次无参尝试:P.563 (ITU-T, 2004) 用 LPC 声道模型 + 谱平坦度等手工特征规则映射到 MOS,与主观 PCC 只有 0.7 左右;E-Model (ITU-T G.107, 1998) 干脆不看音频,从编解码类型、丢包率、延迟、抖动这些网络参数直接推 R-factor 再映射 MOS,因为算得便宜曾在 2000 年代 VoIP/IPTV 运营商 QoS 监控上落地过。
这一代基本进博物馆了 。P.563 精度不够,被后面 DNN 无参系(DNSMOS/NISQA)全面碾压;E-Model 对 AI 降噪、TTS 失真、神经编解码完全无感知------它只知道网络抖动。原则 :有参精度 ≥ 无参,做实验室评测能拿到 ref 就上 PESQ/POLQA/ViSQOL;真需要无参,直接跳到第 3 代及以后(DNSMOS Pro / NISQA / UTMOSv2),别在这一代上停留。
七、第 3 代:DNSMOS / NISQA / MOSNet------DNN 无参的爆发
2019 年后深度学习一波打进来,跳过手工声学特征,端到端从波形/谱图预测 MOS。核心动机是:真实业务场景没有 clean reference,但有一堆已标注 MOS 的语料,那就让网络自己学。
7.1 MOSNet (Lo et al., 2019)
开山之作 。CRN 结构(CNN + BLSTM + Attention Pooling + Dense 输出 MOS),训在 VCC2018 语料上。意义大于精度 ------证明了端到端预测 MOS 这条路走得通。GitHub lochenchou/MOSNet,MIT,TF1 老代码,现在只做学术复现 baseline。
7.2 DNSMOS (Microsoft, 2020)
伴随 DNS Challenge 出的评估工具,这一代真正改变工业界的选择 。输入单声道 9 秒 16 kHz 音频,Log Mel 谱图过几层 CNN + Dense,输出 3 个 1--5 分:SIG (语音保真)+ BAK (噪声抑制)+ OVRL(整体)。训练标签走微软自组织的 P.808 众包听测。
三个改动组合起来对工业界是降维打击:三维分离 (降噪模型改了知道是语音更清还是噪声更干净)、DNS Challenge 生态 (微软官方指标,参赛队都拿它调,训练分布覆盖极广)、推理便宜(ONNX CPU 单条 <100ms)。
微软原始权重是研究许可 ,商用有法律风险。GitHub microsoft/DNS-Challenge 提供 ONNX 文件:
python
# 从 microsoft/DNS-Challenge 拉 sig_bak_ovr.onnx (~1MB)
import numpy as np, librosa, onnxruntime as ort
INPUT_LEN = int(9.01 * 16000) # 144160
def dnsmos_score(wav_path):
sess = ort.InferenceSession('sig_bak_ovr.onnx', providers=['CPUExecutionProvider'])
wav, _ = librosa.load(wav_path, sr=16000)
while len(wav) < INPUT_LEN:
wav = np.concatenate([wav, wav])
seg = wav[:INPUT_LEN].astype(np.float32)[None, :]
sig, bak, ovr = sess.run(None, {sess.get_inputs()[0].name: seg})[0][0]
# 官方多项式后校准
sig = np.poly1d([-0.08397631, 1.22083953, 0.0052439])(sig)
bak = np.poly1d([-0.13166888, 1.60915514, -0.39604546])(bak)
ovr = np.poly1d([-0.06766283, 1.11546468, 0.04602535])(ovr)
return sig, bak, ovr
sig, bak, ovr = dnsmos_score('wav/算法处理3.wav')
print(f'DNSMOS SIG={sig:.4f} BAK={bak:.4f} OVRL={ovr:.4f}')
# DNSMOS SIG=3.5057 BAK=4.0442 OVRL=3.2235
死穴:编码失真下的反向偏置 ------第三章跑过的"电话带压缩版 gTTS"样本,SIG 反而从 3.59 升到 3.61,人耳明明听着差得多。原因是 DNSMOS 的 SIG 网络训练时看的是"人声 + 背景噪声"混合,学到的高保真特征是中频能量集中、谐波清晰;限带滤波把高频噪声一起削了,SIG 网络反而觉得更干净。不适合评编解码器(Opus/EVS/Lyra),做编码评估要走 POLQA 或 UTMOSv2。
DNSMOS Pro (INTERSPEECH 2024) :KTH 团队 fork 的明确 MIT 许可 版本,模型缩尺寸更适合 VoIP 端侧,只用 MOS 当 label,输出高斯后验 (mean + variance)给不确定度。GitHub fcumlin/DNSMOSPro,torch.jit 加载即用。新项目从零起直接上 DNSMOS Pro,绕开原版微软权重的商用风险。
从 PESQ 迁到 DNSMOS 是评估流程升级中 ROI 极高的一步:评估从「必须有 clean ref、线上真实录音不可用」直接变成「任何一段线上录音都能打分」,反馈周期从周级降到分钟级。
7.3 NISQA (Mittag et al., 2021)
德国 TU-Berlin 的 Mittag 团队做的工程化最强的无参 MOS 。相比 DNSMOS 两处提升:五维诊断 (MOS + Noisiness / Coloration / Discontinuity / Loudness)比三分更细;训练数据更广(NISQA Corpus 14000+ 样本,覆盖电话、VoIP、TTS、合成语音)。架构是 CNN 提帧特征 → Self-Attention 聚合 → Attention Pooling → 5 个回归头。
明确开源 (MIT),GitHub gabrielmittag/NISQA:
python
# git clone https://github.com/gabrielmittag/NISQA && pip install -r requirements.txt
# 在 NISQA 仓库根目录执行
from nisqa.NISQA_model import nisqaModel
args = {'mode': 'predict_file', 'pretrained_model': 'weights/nisqa.tar',
'deg': 'wav/算法处理3.wav', 'output_dir': './out',
'ms_channel': None, 'tr_bs_val': 1, 'tr_num_workers': 0}
result = nisqaModel(args).predict()
print(result[['mos_pred', 'noi_pred', 'dis_pred', 'col_pred', 'loud_pred']].iloc[0].to_dict())
# {'mos_pred': 3.7773, 'noi_pred': 4.1383, 'dis_pred': 4.1277, 'col_pred': 3.8769, 'loud_pred': 4.2332}
ANS/AEC 评估建议同时保留 DNSMOS 和 NISQA:DNSMOS 三分适合看降噪总体效果,NISQA 五维适合定位问题在哪。只保留一个选 NISQA------诊断维度(尤其 Discontinuity 对 AEC 双讲切换敏感)对算法迭代的信息量更大。
八、第 4 代:SSL-MOS / UTMOS / UTMOSv2------预训练大模型上位
2022 年是 MOS 预测的分水岭。VoiceMOS Challenge 首次举办,冠军 UTMOS 把 SRCC 从 0.85 一路推到 0.988(system-level),从此 从头训 CNN 这条路基本被判死刑------所有新工作都在 wav2vec 2.0 / HuBERT / WavLM / Whisper 这些 SSL backbone 上做增量。
8.1 SSL-MOS:SSL backbone + 小 head
wav2vec 2.0 / HuBERT / WavLM 这些模型在几万小时无标签语音上预训练,学到的隐层表示已经天然对语音质量敏感------重建被 mask 掉的段时,噪声、失真、断续这些质量因素直接影响重建损失。拿它们冻结/微调后接一个小 head 回归 MOS,效果碾压从头训的 CNN。最小实现:
python
import torch
from transformers import Wav2Vec2Model
class SSLMoS(torch.nn.Module):
def __init__(self):
super().__init__()
self.backbone = Wav2Vec2Model.from_pretrained('facebook/wav2vec2-base')
self.head = torch.nn.Sequential(
torch.nn.Linear(768, 128), torch.nn.ReLU(), torch.nn.Linear(128, 1))
def forward(self, wav):
pooled = self.backbone(wav).last_hidden_state.mean(dim=1)
return self.head(pooled).squeeze(-1)
BVCC 数据集(VoiceMOS 2022 官方语料,7106 条 TTS/VC 样本 × 8 名听者主观打分)+ MSE loss 训练,60 行网络在 BVCC utterance-level SRCC 就能到 0.87------碾压 MOSNet (0.63) 和 DNSMOS (0.68)。
8.2 UTMOS(VoiceMOS 2022 冠军)
在 SSL-MOS 基础上加三个 trick,全部围绕降低 MOS label 的噪声:
- Listener Embedding :每样本带 8 个听者的个体打分和 ID,显式建模「每个听者的偏好」(
predicted_MOS = base_MOS + listener_bias(id)),推理时对听者 ID 平均。OOD track 上 MSE 从 0.636 拉到 0.378,几乎减半。 - Pairwise Contrastive Loss:随机采一对样本让分差符号跟真实 MOS 分差符号一致,专门优化 SRCC。
- Phoneme + Domain Embedding:ASR 转音素序列 + "BVCC / OOD" 域标签,都塞进 head 作条件。
MIT 开源 ,GitHub sarulab-speech/UTMOS22,一行加载即用:
python
# pip install torch torchaudio
import torch, torchaudio
predictor = torch.hub.load("tarepan/SpeechMOS:v1.2.0", "utmos22_strong", trust_repo=True)
wave, sr = torchaudio.load('wav/算法处理3.wav') # 也可以直接传 numpy 数组
score = predictor(wave, sr) # tensor scalar
print(f'UTMOS: {score.item():.4f}')
# UTMOS: 2.2178
死穴:跨域打分系统性偏移 ------UTMOS 训在 TTS/VC 语料上,第三章实测已经看到:ANS/AEC 算法处理 3 和 TTS Edge Xiaoxiao 在 DNSMOS OVRL 眼里都是 3.2,UTMOS 却分别给 2.23 和 3.83,差 1.6 分。歌唱评估任务(如 ASAE Challenge)直接搬 UTMOSv2 baseline,SRCC 只在 0.4 出头就已被公开报告过------歌唱语音的 pitch stability、vibrato、breath sound 在 BVCC 里没对应样本,UTMOS 只会当"奇怪的 TTS"打低分。跨域用 UTMOS 的应对:首选换 UTMOSv2(下节),或用 SHEET 工具箱在目标域小数据集上重训 head;同域相对排序还能信,跨域绝对分完全不能信。
8.3 UTMOSv2(VoiceMOS 2024 霸榜)
VoiceMOS 2024 Track 1 的 16 个指标里,UTMOSv2 拿了 7 个第一 + 9 个第二 。三处改动:双分支 stacking ensemble (strong learner 是 wav2vec 2.0 finetune + BLSTM + clipless MSE + contrastive;weak learner 把 wav2vec2/HuBERT/WavLM 的 utterance embedding 各喂进 Ridge/SVR/RF/LightGBM/GP;三层 stacking 聚合)、显式 domain embedding 、Phoneme encoder(ASR + DBSCAN 音素归一化)。
MIT 开源 ,GitHub sarulab-speech/UTMOSv2,官方 utmosv2 包一行加载:
python
# pip install git+https://github.com/sarulab-speech/UTMOSv2.git
import torch, random, numpy as np, utmosv2
# UTMOSv2 每次前向有随机性(fold 采样),要复现必须固定 seed
torch.manual_seed(42); np.random.seed(42); random.seed(42)
if torch.cuda.is_available(): torch.cuda.manual_seed_all(42)
model = utmosv2.create_model(pretrained=True) # 首次会下 fusion_stage3 权重
mos = model.predict(input_path='wav/算法处理3.wav') # 支持文件路径 / numpy / tensor
print(f'UTMOSv2: {mos:.4f}')
# UTMOSv2: 2.1836
⚠️ 注意 :UTMOSv2 单次调用结果不稳定(fold ensemble 内部有随机采样),不固定 seed 时同一样本连跑 3 次可能出 1.97 / 2.95 / 1.95。生产用需要固定 seed 或多次平均。
对 TTS/VC/codec 论文,"SSL-MOS baseline" 现在事实上就是它 。相较 UTMOS 的最大收益不是精度,是跨域鲁棒性------domain embedding + stacking 让它在新数据集上不训 head 直接用也能保持稳定。但对完全新品类(歌唱美学),UTMOSv2 也只是把 SRCC 从 0.4 拉到 0.5 左右,还是不能用。
8.4 HighRateMOS (NVIDIA, ASRU 2025)
痛点很具体:现有 SSL-MOS 全训在 16 kHz,遇到 48 kHz HD Voice / 音乐会打分系统性偏低------wav2vec 2.0 预训练时就没见过高采样率。做法是三路 ensemble------采样率 learnable embedding + wav2vec 2.0 SSL embedding + multi-scale CNN + MFCC,AudioMOS 2025 Track 3 八个指标里五个第一。代码 NVIDIA 尚未完全开源(截至 2026-07),会随论文放出。
8.5 重新思考 MOS label 本身
Kondo & Kameoka 有两篇挑战「MOS = 听者算术平均」这个前提的工作:N-lowest MOS (2025) 假设听者更看重低质段,取最低 N 个打分当代表值(N=6),MOSNet target 换成 Nlow-MOS 后 LCC/SRCC 都涨;Quantized Distribution Fitting (ICASSP 2025) 假设听者内心是连续分四舍五入到 1--5 造成量化噪声,反推潜连续分布的峰值当代表值,比 N-lowest 更通用。
启示是:SSQA 模型不准,可能不全是模型背锅,MOS label 本身就有噪声。换 target 聚合方式比换 backbone 有时更划算------2024--2025 最容易被忽略但性价比最高的方向。
九、第 5 代 SpeechQualityLLM (ICASSP 2025)------从「打分」到「解释打分」
前四代都在做一件事:给一段音频输出一个数。但工业界越来越多的需求是"给客户或产品经理看评测报告,光甩个 3.7 不够------得说清哪里差、差几分、为什么差"。这就是第 5 代的动机。
第一个把 audio encoder + LLM 拼起来专做质量评估的公开工作。backbone 走 SALMONN / Qwen-Audio / Qwen2-Audio 这类多模态基座;训练 用 NISQA 语料 + 模板 QA 对 finetune,覆盖 MOS 总分 + 四维诊断(噪声/音染/不连续/响度);输出是生成文本再解析数值------比如:"The speech quality is fair (3.6). Main issue is noticeable background noise (noisiness: 2.8), slight discontinuity (3.9). Coloration and loudness are acceptable."
意义不在于精度(NISQA 保留集上双端 MAE=0.41, Pearson=0.86 跟专用小模型打平),而在于一体化生成------模型能追问、能对比、能模拟不同听者。"这段跟上一段比哪个更好?""模拟一个 30 岁工程师听者的判断"这类交互能力,是小模型完全给不了的。
部分开源 (截至 2026-07):Qwen2-Audio backbone MIT,论文放出了 finetune 脚本和数据处理代码,打分器精调权重需按学术协议申请,公开渠道暂时拿不到。所以博客里跑不到 SpeechQualityLLM 的真实分------但可以跑它的 backbone Qwen2-Audio-Instruct,看看未经 MOS 精调时 Audio-LLM 的原生打分能力:
python
# pip install transformers accelerate librosa
from transformers import Qwen2AudioForConditionalGeneration, AutoProcessor
import torch, librosa
mp = 'Qwen/Qwen2-Audio-7B-Instruct'
processor = AutoProcessor.from_pretrained(mp)
model = Qwen2AudioForConditionalGeneration.from_pretrained(mp, torch_dtype=torch.float16, device_map='cuda')
def rate(path):
wav, _ = librosa.load(path, sr=16000)
conv = [{'role':'user','content':[
{'type':'audio','audio':wav},
{'type':'text','text':'Rate this speech quality on a 1-5 scale (MOS). '
'In one line comment on noise, distortion, and naturalness.'}
]}]
text = processor.apply_chat_template(conv, add_generation_prompt=True, tokenize=False)
inputs = processor(text=text, audio=[wav], sampling_rate=16000, return_tensors='pt').to('cuda')
out = model.generate(**inputs, max_new_tokens=120, do_sample=False)
return processor.batch_decode(out[:, inputs.input_ids.size(1):], skip_special_tokens=True)[0]
for tag, path in [('算法处理1(过度抑制)', 'wav/算法处理1.wav'),
('算法处理3(保守)', 'wav/算法处理3.wav'),
('电话带压缩 gTTS', 'wav/tts_bad_telephone.wav')]:
print(f'=== {tag} ===\n{rate(path)}\n')
跑出来的 raw output(三个音质差异很大的样本):
=== 算法处理1(过度抑制) ===
4.5/5 - The speech is clear, concise, and has minimal background noise or distortion. Naturalness is also good.
=== 算法处理3(保守) ===
4.5/5.0 - clean audio with minimal distortion, sounds natural.
=== 电话带压缩 gTTS ===
4.5/5 - The speech is clear, concise and has minimal background noise or distortion. Naturalness is also good.
通用 Qwen2-Audio 三个样本全打 4.5 ------包括人耳一听就是"客服热线音质"的电话带压缩 gTTS。这恰好说明通用 Audio-LLM 没经过 MOS 精调时,打分能力约等于零,必须靠 NISQA 语料上的定向 finetune(也就是 SpeechQualityLLM 做的事)才能真正预测 MOS。
推理成本是关键约束 :7B 模型单次前向几百 ms(GPU),比 UTMOSv2 慢 10-50 倍------CI/CD 里每次改动跑 10000 条评测直接爆算力预算。所以 SpeechQualityLLM 系目前不适合替代 UTMOSv2 做日常迭代,但特别适合「产品季度评审报告」这类少批量高价值场景------给业务方看的东西必须能解释,纯数值给不了信任。
十、TTS 垂直域评估补充
前面五代主要是通用 SSQA 主线。TTS 作为最活跃的合成语音领域,圈内实际用的评估手段比 P.800 ACR 广得多:主观协议有 5 个变体,客观算法有几个 TTS 专属分支,评估表里 MOS 从来不单打独斗还并列 SIM/WER/F0 一整排。
10.1 主观协议:ACR 不够用的时候
TTS 论文里实际出现的主观协议不止 ACR 一个,五种分工不同:
| 协议 | 全称 | 量表 | 典型值 | TTS 场景 |
|---|---|---|---|---|
| ACR | Absolute Category Rating (P.800) | 1--5 | 合格 ≥4.0 | 自然度 MOS,最通用 |
| SMOS | Similarity MOS | 1--5 | 合格 ≥3.5 | 说话人相似度------VC / zero-shot TTS 必测 |
| CMOS | Comparative MOS | -3...+3 | 优势 +0.3 显著 | 两个 TTS 系统 A/B 比,统计效力比 ACR 高 |
| S-MOS / M-MOS | Sentence / Multi-sentence MOS | 1--5 | 同 ACR | 单句自然度 vs 长文拼接整体感 |
| MUSHRA | ITU-R BS.1534 | 0--100 连续 | REF ~90,好 TTS ~70-80 | 高分区分------模型都 4.2+ 时 ACR 挤一起拉不开 |
注:S-MOS / M-MOS 并非 ITU 标准命名,是 MSStyleTTS (2023) 论文里为区分单句/长文评测提出的简写,圈内未广泛采用;这里用来指代"单句 vs 长文"这个评测维度的必要性------长文 TTS 单句好不代表拼起来不崩。
MUSHRA 在 TTS 里的重要性 :VITS 在 CMOS 上跟 REF 几乎打平(≈ -0.10),但 MUSHRA 差 16 分(REF 84.2 vs VITS 67.7)------听者隐性以"标注 REF"为锚,系统跟 REF prosody 不一致就被压低。高分 TTS(>4.3)论文现在普遍走 MUSHRA + NMR 变体(No Mentioned Reference,把 REF 藏成匿名系统之一)。
跳出 5 级量表的新范式:Audio Turing Test (ATT, 2025) ------中文 LLM-TTS 阵营(Seed-TTS 那类)提的评测新协议,不做 1--5 打分,改做三元判断 (真人 / 合成 / 理由)+ trap item + 随机分配。857 名中文听者的实测里,Seed-TTS 的 human-likeness 只有 0.4,但传统 MOS 报 4.5+------MOS 饱和后 ATT 更能拉开 。配套的 Auto-ATT 是 Qwen2-Audio-Instruct 在 ATT 数据上 finetune 出来的自动评估器,比 UTMOS 在 trap clip 上稳。
10.2 客观算法:TTS 场景常用
10.2.1 SQUIM (Meta, 2022)
torchaudio 内置 (torchaudio.pipelines.SQUIM_OBJECTIVE / SQUIM_SUBJECTIVE),两个用法:
- OBJECTIVE:无参估计 STOI / PESQ / SI-SDR 三个数------不直接给 MOS,但把有参指标"预测出来"了,可以用在没有 clean ref 的线上场景
- SUBJECTIVE :Non-matching reference MOS------不用干净 ref,用同一说话人的另一条正常语音当参考,SSL-MOS 变体
python
# torchaudio 内置,无需额外安装
import torchaudio, soundfile as sf, librosa, numpy as np, torch
def load16k(p):
w, sr = sf.read(p)
if w.ndim > 1: w = w.mean(1)
if sr != 16000: w = librosa.resample(w.astype(np.float32), orig_sr=sr, target_sr=16000)
return torch.from_numpy(w.astype(np.float32)).unsqueeze(0)
obj = torchaudio.pipelines.SQUIM_OBJECTIVE.get_model()
sub = torchaudio.pipelines.SQUIM_SUBJECTIVE.get_model()
deg = load16k('wav/算法处理3.wav')
ref = load16k('wav/参考信号.wav') # non-matching ref(同说话人的另一条即可)
n = min(deg.shape[-1], ref.shape[-1])
with torch.no_grad():
stoi_p, pesq_p, sisdr_p = obj(deg[:, :n])
mos_sub = sub(deg[:, :n], ref[:, :n])
print(f'SQUIM_OBJ STOI={stoi_p.item():.4f} PESQ={pesq_p.item():.4f} SI-SDR={sisdr_p.item():.4f}')
print(f'SQUIM_SUB MOS={mos_sub.item():.4f}')
# SQUIM_OBJ STOI=0.9268 PESQ=2.6278 SI-SDR=12.6063
# SQUIM_SUB MOS=4.4898
用途:有旁支干净音时(同说话人的另一条录音),SQUIM_SUBJECTIVE 比纯无参稳。torchaudio 内置这一点让它工程集成成本极低。
10.2.2 Audiobox Aesthetics (Meta, 2024)
不回归一个数,输出四个维度,每个都跟主观质量相关但侧重不同:
- CE (Content Enjoyment) --- 听着"享受"程度
- CU (Content Usefulness) --- 内容有用性
- PC (Production Complexity) --- 制作复杂度
- PQ (Production Quality) --- 制作质感
分数是 1--10 尺度(不是 1--5,跟 MOS 系刻度不同,直接比数值没意义)。
python
# pip install audiobox-aesthetics
from audiobox_aesthetics.infer import initialize_predictor
predictor = initialize_predictor() # 首次下 Meta 权重
r = predictor.forward([{'path': 'wav/算法处理3.wav'}])
print(r)
# [{'CE': 4.6830, 'CU': 5.2101, 'PC': 1.7022, 'PQ': 6.4570}]
用途:TTS 产品评测需要"可解释多维分"时------PQ 高但 CE 低说明"技术上合格但听着无聊",能反过来指导数据 / 韵律优化。TTSDS2 benchmark 里 CE/CU 在 Kids/Wild 域 SRCC 到 0.58--0.60,比 DNSMOS 在 OOD 域稳。
10.2.3 TTSDS2 (Minixhofer et al., 2024/2026)
跟前面所有算法不同定位 ------TTSDS2 是分布级基准 ,不评单条音频。给一批 TTS 输出 + 一批真人参考,算两批语音在 speaker / prosody / content / environment 多维 embedding 空间里的 Frechet 距离(类似图像域 FID、音乐域 FAD 的语音版本),输出一个反映"这个 TTS 系统整体跟真人差多远"的分数。
用途不是逐条评分,是系统级漂移预警:TTS 模型换 checkpoint,UTMOSv2 平均分没变(还是 4.1),但 TTSDS2 掉了 → 说明分布形状变了(韵律多样性下降、口音塌成单模式),从平均分看不出来。跨系统 benchmark 里也比"报平均 MOS + 方差"更简洁------一个数反映整个分布多接近真人。
开源 (MIT),pip install ttsds。使用时要提供两个目录(各至少 20+ 条 wav,论文建议 100+),本博客只有 9 条样本估不出稳定分布,跑不出有意义结果------所以这里只讲清定位,不放代码。TTSDS2 在 Clean/Noisy/Wild/Kids 各域跟主观 MOS 的 system-level SRCC 都 0.6+,跨域比 UTMOSv2 / DNSMOS 都稳,值得纳入 TTS 迭代的定期评估流程。
10.2.4 Zoomed-in bias(TTS 独有的评估问题)
UTMOSv2 论文专门提的:听测里人倾向把 5 级尺子拉长到用完 ,如果一批样本全是高质量 TTS(top 25% 或 top 12%),中档系统会被系统性压低------这就是 VoiceMOS 2024 Track 1 的 zoomed-in 设定。传统 MOS 预测模型(包括 UTMOSv1)在这种分布上会低估高分 ,UTMOSv2 靠 domain embedding + stacking 缓解。推论:TTS 模型已 4.3+ 时,别拿 UTMOSv1 的 raw 分横向比不同 paper,要么换 UTMOSv2,要么走 MUSHRA / ATT。
10.3 配套指标:MOS 从不单打独斗
TTS 评估表里,MOS 旁边一定站一排"技术层"指标------不测好听度,测"说得对不对 / 像不像 / 韵律准不准"。
10.3.1 SIM:说话人相似度
VC / zero-shot TTS 的核心指标。用 ECAPA-TDNN / RawNet3 / X-Vector 提说话人 embedding,算余弦相似度。SIM > 0.75 算合格。
python
# pip install speechbrain
import torch, soundfile as sf, librosa, numpy as np
from speechbrain.inference.speaker import EncoderClassifier
def load16k(p):
w, sr = sf.read(p)
if w.ndim > 1: w = w.mean(1)
if sr != 16000: w = librosa.resample(w.astype(np.float32), orig_sr=sr, target_sr=16000)
return torch.from_numpy(w.astype(np.float32)).unsqueeze(0)
model = EncoderClassifier.from_hparams(source='speechbrain/spkrec-ecapa-voxceleb', savedir='/tmp/ecapa')
def sim(a, b):
ea = model.encode_batch(load16k(a)).squeeze()
eb = model.encode_batch(load16k(b)).squeeze()
return torch.nn.functional.cosine_similarity(ea, eb, dim=0).item()
print(f'SIM(参考, Edge Xiaoxiao) = {sim("wav/参考信号.wav", "wav/tts_edge_xiaoxiao.wav"):.4f}')
print(f'SIM(参考, Edge Yunxi) = {sim("wav/参考信号.wav", "wav/tts_edge_yunxi.wav"):.4f}')
print(f'SIM(参考, 参考 self) = {sim("wav/参考信号.wav", "wav/参考信号.wav"):.4f}')
# SIM(参考, Edge Xiaoxiao) = 0.3122
# SIM(参考, Edge Yunxi) = 0.1782
# SIM(参考, 参考 self) = 1.0000
样本里参考信号跟两个 Edge TTS 是不同说话人,SIM 0.18--0.31 说明确实不像;参考跟自己 = 1.0 是健全性检查。真做 zero-shot TTS 评测时,把合成音跟 target speaker 的 prompt 音配对算 SIM。
10.3.2 WER / CER:文本一致性
"说对了没"。TTS 输出过一遍 ASR,跟原文本算词/字错误率。中文场景常用 Whisper 或 GPT-4o-Transcribe。
python
# pip install openai-whisper jiwer
import whisper
from jiwer import cer
m = whisper.load_model('base') # 生产用 large-v3 更准
gt = '仓库的后面是一间小屋,太阳从东方升起来。'
for tag, p in [('Edge Xiaoxiao', 'wav/tts_edge_xiaoxiao.wav'),
('gTTS', 'wav/tts_gtts.wav'),
('电话带压缩', 'wav/tts_bad_telephone.wav')]:
text = m.transcribe(p, language='zh')['text'].strip()
print(f'{tag:15s} CER={cer(gt, text):.3f} → {text}')
# Edge Xiaoxiao CER=0.550 → 殘酷的後面是一間小屋,太陽從東方盛起來
# gTTS CER=0.500 → 殘酷的後面是一間小屋太陽從東方升起來
# 电话带压缩 CER=0.500 → 蒼褲的後面是一間小屋太陽從東方升起來
CER 0.5 主要是 Whisper base 简繁差异导致("仓库"→"殘酷"、"升起来"→"盛起来"),生产用 large-v3 + 简繁归一化后一般能到 CER < 0.05。方法本身有效,示例的绝对值仅供演示。
📊 WER/CER 常见干扰项(大规模评测时 raw CER 数字里的差异不全是 TTS 说错了,很大一部分是 ASR/参考侧的噪声):
类别 举例 ASR 识别错误 / 幻听 音近替换 night → light、work → walk;严重幻听some quick news → sun quick nose;长句里某段直接漏识别同义转写 假名↔罗马字 ありがとう ↔ arigatou;拼音↔汉字nǐ hǎo ↔ 你好;符号↔文字% ↔ 百分之;数字↔汉字1024 ↔ 一千零二十四空格/分词不匹配 NewYork ↔ New York;Los Angeles ↔ LosAngeles;i o s ↔ ios语种混用 发 PPT → 发 power point;日文汉字被读中文音;Hola → Oh law同音/近音字 在↔再、做↔作、的↔得↔地;专有名词生僻字钰→玉、翊→亦实操建议:直接拿 raw CER 当合格线会被这些误伤。评测前必须做归一化------简繁统一、数字/符号 → 汉字、罗马字 → 假名、去空格差异;语种混用和同音字样本要人工过一遍,不能直接算进平均 CER。
10.3.3 F0 RMSE / MCD / 音素时长
不展开代码,但要知道:F0 RMSE (半音单位)诊断疑问句语调平淡、句末延长缺失;MCD 是老派谱失真指标(Mel-Cepstral Distortion),声码器论文里仍在用;音素时长误差 配合 F0 诊断韵律。这三个都可以用 librosa + pyworld 或 Montreal Forced Aligner 算出来,工程量不大。
10.4 一句话选型
写到这里全文的工程判断收拢一下,读者关掉页面时脑子里应该留下这一段:
💡 按场景选打分器:
- ANS/AEC 迭代:DNSMOS Pro(商用许可安全)+ NISQA(诊断维度定位问题)交叉验证。
- TTS/VC 日常评测:UTMOSv2(BVCC 训的,TTS 域最稳)。
- 高分 TTS(>4.3):ACR 分挤一起拉不开,走 MUSHRA-NMR 或 ATT。
- 要可解释报告:Audiobox Aesthetics(四维 1-10)+ SpeechQualityLLM(文本诊断,离线场景)。
- 系统级漂移预警:TTSDS2(不评单条,评整批 vs 真人分布距离)。
- 有旁支干净音(同说话人的另一条录音):SQUIM_SUBJECTIVE(torchaudio 内置,比纯无参稳)。
- 运营商合规盖章:绕不开 POLQA(闭源,10-50 万美元授权)。
- 说话人相似度:SMOS 主观 + ECAPA-TDNN SIM 客观。
- 文本一致性:Whisper large-v3 CER + 归一化预处理。
⚠️ 唯一硬性红线 :不要跨打分器比绝对分。PESQ=2.34、DNSMOS=3.20、UTMOS=2.23 都对,各自刻度不同。选定一个打分器就盯一个,评估报告始终用同一个的同一版本,横向比较靠这个打分器内部的分数差,不靠"数值 3.2 大于 2.5 所以更好"。