全部文章

· Casimiro Ferreira· 2 分钟阅读

不靠听审团衡量语音质量

  • speechonnxmetrics
  • TTS
  • ONNX
  • evaluation

一个降噪模型发布了新的检查点。一个 TTS 声音在更多数据上被重新训练。一条声音克隆流水线换掉了它的声码器。在每一种情况下,都得有人回答:输出比之前更好还是更差?“我听着觉得更好”这种说法无法规模化。语言换成一门你不会说的语言时它就失效了;要比较的不是两个而是二十个检查点时它就失效了;每次提交都需要检查、而不是偶尔手动检查一次时,它也失效了。

对”听起来是否更好”这个问题,严谨的答案是一个 平均意见得分(MOS):把音频放到一组听众面前,请每个人打 1 到 5 分,再取平均。MOS 之所以是语音质量的标准指标,正是因为它问的是那个真正要紧的问题——一个人类会不会觉得这可以接受——而不是这个问题的替代品。它也很昂贵。招募一个听审小组、持续一致地运作它、并为一个小团队所发布的每一种语言、每一种录音条件、每一个模型版本重复这个过程,这不是一个听审团能跟得上的节奏。

speechonnxmetrics 是一个库,用来在没有听审团的情况下、在每一次构建时,去逼近那个判断。它把自己的指标分成三个家族,而为具体情况选对家族,比任何一个单独的数字都更重要。

三个家族,三个问题

无参考 MOS 估计器 是训练出来、单凭音频本身就能预测一个听审团会给出什么评价的神经网络。它们不需要一个干净的原始版本——只需要你想评判的那个输出。当没有可供比较的真值时用这个家族:给一个 TTS 系统的输出打分,或是在降噪之后检查一段真实的、本就已经劣化的录音。

侵入式指标 需要一个匹配的干净参考音频,衡量它与劣化信号之间的距离。当你自己人为制造了劣化、并且仍然持有干净的原始版本时用这个家族:你把一段已知良好的录音喂给了一个编解码器、一个带宽扩展模型,或一个声音转换器,想知道输出偏离源音频有多远。

基于 ASR 的文本指标 用一个语音识别器转录输出,再把转录文本与预期文本做差异比较。这能捕捉到另外两个家族都捕捉不到的东西:一段听起来完全自然、干净,却说错了词的音频。一个无参考 MOS 预测器评判的是自然度,而非正确性——一句流利的读错音照样能得高分。一个侵入式指标需要一个参考波形,而不是一个参考句子。只有比较文本才能抓到一个错词。

这个库通过一个函数暴露这些指标:

import speechonnxmetrics as s

# No-reference: only the output needed, no ground truth exists
s.score("output.wav", ["utmos"])

# Intrusive: needs a clean reference, ref= is required
s.score("degraded.wav", ["stoi", "mcd", "si_sdr"], ref="clean.wav")

文本指标存在于一个独立的模块 speechonnxmetrics.asr 中,因为它们比较的是字符串,而不是音频——s.score() 只分发接受波形的指标。

无参考 MOS:如何读懂这些数字

库中提供四个 MOS 估计器,每个都返回一个 1 到 5 分的数值,分数越高越好——与人类听审团所用的量表一致:

指标维度训练数据是否可商用
utmos单一自然度分数合成语音(VoiceMOS Challenge)
dnsmossig / bak / ovrl(语音质量 / 背景噪声 / 总体)ITU-T P.835
dnsmos_p808单一众包听测 MOSITU-T P.808
sigmos7 个维度(coldiscloudnoisereverbsigovrlITU-T P.804
nisqamos 加上 noi/dis/col/loud 细分NISQA-v2否——CC BY-NC-SA 4.0

nisqa 是整个库中唯一一个权重非商用的指标。其他四个都采用 MIT 许可。speechonnxmetrics 不会替你过滤这一点;它会说明许可证,把选择权留给调用方。

下面是真实音频的评分情况。把库自带的固定测试素材——一段干净录音(source.wav)和同一片段经神经编解码器重新合成的版本(facodec_aria.wav)——分别喂给 UTMOS:

>>> s.score("source.wav", ["utmos"])
{'utmos': 4.41}
>>> s.score("facodec_aria.wav", ["utmos"])
{'utmos': 3.21}

干净录音的分数接近量表顶端,这是应该的——它是真实的人类语音,而非合成的。编解码重新合成的版本掉了超过一整分。比起任何一个单独的数字,这个差距才是有用的信号:它告诉你这个编解码器引入了可听见的劣化,也给了你一个可以在调优编解码器时持续追踪的数字。

对同一段干净录音跑 DNSMOS:

>>> s.score("source.wav", ["dnsmos"])
{'dnsmos.sig': 3.45, 'dnsmos.bak': 3.60, 'dnsmos.ovrl': 2.93}

是三个数字,而不是一个,而且它们之间存在分歧——ovrl 明显低于 sigbak 两者。这种分歧是有信息量的,而不是一个 bug:ovrl 是 P.835 对整体聆听体验的评分,它往往比任何一项单独的分量分数所暗示的更严厉地惩罚一段录音,对一段真实世界的录音尤其如此,而非一段录音棚录音。当 bak 偏低时,去找背景噪声;当 sig 偏低时,去找语音层面的伪影——削波、丢帧、机械音色。对同一段音频报告不止一个预测器:它们训练所用的数据不同,会以有信息量的方式产生分歧,而同一段音频上两个独立预测器之间的巨大差距,正是提醒你该去亲耳听一听的信号。

侵入式指标:如何读懂这些数字

库中有十一个基于参考的指标,衡量与一个干净原始版本之间的距离。最值得先了解的几个:

指标范围方向衡量什么
stoi / estoi0–1越高越好短时客观可懂度——有多少 内容 保留了下来,与听起来自然与否无关
si_sdr / sdr / snrdB,无界越高越好信号失真比 / 信噪比
mcddB,无界越低越好mel 倒谱失真——频谱包络距离,一个经典的 TTS/VC 质量指标
log_f0_rmse无界越低越好音高轮廓误差
lsd / msddB越低越好对数频谱 / mel 频谱距离

注意方向是相反的:STOI 和 SDR 家族在质量更好时数值上升;MCD、音高误差和频谱距离则下降。读表格时把这两者搞混是很容易犯的错误。

把同一个编解码重新合成版本对照它的干净源音频打分:

>>> s.score("facodec_aria.wav", ["stoi", "mcd", "si_sdr"], ref="source.wav")
{'stoi': 0.662, 'mcd': 10.46, 'si_sdr': -26.94}

在一个 1.0 为完美匹配的 0 到 1 量表上,0.66 的 STOI 说明可懂度确实受到了实质性打击——这明显低于一段轻度处理的录音应有的分数。约 −27 dB 的 SI-SDR 证实了这一点:只要失真能量超过信号能量,SI-SDR 就会是负值,而一个很大的负数意味着结构性的重大改变,不只是添加了噪声。10.46 dB 的 MCD 偏高;那些听起来明显是合成的、但仍保持说话人一致性的已发布 TTS 系统,通常落在个位数区间,因此 10 以上的数值表明重新合成版本与原始版本之间存在明显的频谱包络漂移。

基于 ASR 的指标:如何读懂这些数字

五个文本指标都来自参考转录文本与识别假设文本(音频被实际转录成的内容)之间的一次莱文斯坦对齐:

指标范围方向含义
wer≥ 0(通常 0–1,可超过 1)越低越好词错误率:替换数 + 删除数 + 插入数,除以参考词数
cer0–1越低越好同样的思路放到字符层面——对细微的拼写/分词不一致更宽容
mer0–1越低越好匹配错误率
wil0–1越低越好丢失的词信息
wip0–1越高越好保留的词信息(1 − wil

一个实例:参考文本 “the quick brown fox jumps over the lazy dog” 对照识别假设 “the quick brown fox jumped over a lazy dog”(一处替换,“jumps” → “jumped”,一处删除,删掉了 “the”):

>>> from speechonnxmetrics import asr
>>> from speechonnxmetrics.asr import BASIC
>>> asr.wer(reference, hypothesis, normalizer=BASIC)
0.222
>>> asr.cer(reference, hypothesis, normalizer=BASIC)
0.116

0.22 的 WER 意味着大约每五个词就有一个出错——是能被注意到、值得听一听的程度。同一对文本上 CER 更低,是因为字符层面的打分,把一处单词替换算作长得多的字符串中的少数几个字符编辑,而不是整个丢失的一个 token;CER 和 WER 回答的是不同的问题,彼此不能直接比较。自然语音上 WER 超过大约 0.3–0.4,通常说明 ASR 系统、或它正在转录的音频,出了真正的问题,而不是舍入误差。

speechonnxmetrics 从不替你对文本做归一化——原始比较会把大小写和标点都算作错误,而当你评判的是发音而非精确的转录格式时,这通常不是你想要的。需要显式传入一个归一化器:BASIC 会转小写并折叠空白,STRICT 还会展开缩写形式,并去除变音符号、标点和填充词。

最重要的一条提醒

这个库中每一个无参考 MOS 数字,都是一个模型给出的预测,而不是对某个事实的测量。UTMOS、DNSMOS、SIGMOS 和 NISQA 各自是在一套特定的听测数据上、在特定的语言和录音条件下训练出来的。一个主要在英语录音棚录音上训练出来的预测器,在面对一门它训练时从未见过的语言、一种它的训练听审团从未评过的口音,或是一种超出其训练分布的录音条件——电话音频、嘈杂的房间、低质量麦克风——时,可能会误判。这个模型并不是在说谎;它是在做外推,而对陌生输入做外推,正是神经网络预测器最不可靠的地方。

把一个预测出来的 MOS 当作证据,而不是当作真相。它在自己擅长的地方是值得信赖的:捕捉大幅度的质量退化、把若干候选相互排序,以及标记出一次需要人类真正去听一听的运行结果。当决策高风险时,它不能替代一个真正的听审团,也不应该在一门底层模型从未被训练来评判的语言或条件上成为最终定论。同时报告多个预测器,并把它们之间的分歧当作”该去听一听”的提示,而不是当作可以平均掉的噪声——这是切实可行的应对办法。

为什么这正是让比较变得可用的关键

以上这些孤立地看都没什么用。当需要在同一个基准上比较若干个引擎时——该默认用哪个 TTS 引擎、哪个 STT 引擎、哪个增强模型——它才变得有用。speechonnxmetrics 正是为评估这套纯 ONNX 语音库——TTS、ASR、降噪、声音克隆——而构建的,这些库发布的逐引擎比较,正是用上面这些指标产出的:对没有真值的系统用无参考 MOS,在存在干净参考音频的地方用侵入式指标,只要转录文本的正确性存疑就用 WER/CER。这正是把”我们选了这个引擎”变成一个别人也能核实的数字的关键。

如果你的项目需要以这种方式评估一门语言、一个引擎或一种录音条件,而目前还没有覆盖到,联系我们,或看看我们的服务