做语音生成(TTS 文本转语音 / VC 音色转换 / SVS 歌声合成)或语音增强的人,多半绕不开一个问题:主观分怎么用一个自动脚本估出来。
MOS (Mean Opinion Score,主观听感均分)本身的定义就是无参考的------找一批 rater 听音频、按 1-5 打分取均值,评的就是"这段音频本身好不好听",跟有没有 clean 参考没关系。问题只是人工打分贵、慢、还漂(不同 rater、不同 session 均分能差 0.3-0.5 MOS),做迭代实验时根本扛不住。
自动化替代大致分两条路:
- 有参考客观 metric (PESQ / POLQA / STOI / ViSQOL):本质是 degradation metric------衡量的是同一段音频经过某种处理后跟原始 clean 参考的距离,天然只适用于降噪 / AEC / 编解码 / 音效这类"有原始信号在手"的场景。放到 TTS / VC / SVS 上根本无参考可对
- 无参考神经预测器(DNSMOS / NISQA / UTMOS / SSL-MOS 系列):直接从波形回归到 MOS 数值,不需要参考。逼近的是"如果找 rater 听这段,他们会打多少分"
本文的主题 SHEET(Speech Human Evaluation Estimation Toolkit)是第二条路里的最新代表------Nagoya University 与 NICT 的 Wen-Chin Huang 团队从 2022 年 SSL-MOS 开始持续迭代,最近把整套 pipeline 打包成 PyTorch 工具箱开源,配套 checkpoint 库 https://huggingface.co/unilight/sheet-models 覆盖 8 个训练数据集 × 多个 SSL 主干的多套权重。
一、从 SSL-MOS 到 SHEET
1.1 神经 MOS 预测器的演进
深度学习之前的 no-reference MOS 打分基本没有工业级方案------传统启发式规则跟主观分相关性长期在 0.5 以下。MOSNet (Lo et al., Interspeech 2019)用 CNN-BLSTM 从 STFT 端到端回归 MOS 开路;SSL-MOS (Cooper et al., ICASSP 2022 · https://arxiv.org/abs/2110.02635)把 wav2vec2 / HuBERT / WavLM 等 SSL 主干接一个池化 + 线性头做 fine-tune,成为后续几乎所有工作的骨架;同期 UTMOS(UTokyo-SaruLab · Saeki et al., Interspeech 2022 · https://arxiv.org/abs/2204.02152)走同一路线,在 VoiceMOS Challenge 2022 main + OOD 两个赛道多项指标居前。
但同分布数字漂亮不等于 OOD 稳。SHEET 论文(Huang et al., TASLP 2026 · https://arxiv.org/abs/2411.03715)提出 MOS-Bench :8 训练集 + 17 测试集覆盖 TTS / VC / SVS / 电话 / 增强 / 混杂噪声,系统对比多数据集训练策略后得到反直觉结论------简单 pooling 稳定不输 AlignNet 这类 domain-aware 方法 ,data variation 比 domain-aware modeling 重要。这直接决定了 SHEET 官方主推的 all8 pooling 权重。
1.2 SHEET 家族一览
SHEET 本身不是新算法------它把上面这条线的代码 + 训练配方 + 权重打包成一个可用工具箱:
| 组件 | 位置与规模 |
|---|---|
| 论文 | https://arxiv.org/abs/2411.03715 · TASLP 2026(v1 2024-11 · v2 2026-04) |
| 代码 | https://github.com/unilight/sheet · PyTorch · 训练/推理/评测 recipe |
| 权重 | https://huggingface.co/unilight/sheet-models · 37 个 checkpoint |
| 模型结构 | 3 种:SSL-MOS · SSL-MOS+MDF · AlignNet |
| SSL 主干 | 4 种:wav2vec2-small · wav2vec2-Large-LL60k · HuBERT-Large-LL60k · WavLM-Large |
| 训练数据组合 | 8 个单集 + 2 种 pooling:all7(不含 urgent2024,用于 SSL-MOS+MDF / AlignNet 变体)· all8(含 urgent2024,用于 SSL-MOS-WavLM-Large 变体,官方默认推荐) |
1.3 三种模型架构
论文 Fig. 1 一张图讲完 SHEET 覆盖的三种结构:

- SSL-MOS(左) :SSL 主干 → 时间池化 → decoder(一个 linear head)→ MOS ∈ 1, 5。主干占大头(WavLM-Large 316M 参数),head 就一个
nn.Linear。fine-tune 时主干全参放开,学习率给 head 大一档、给 backbone 小一档是常规做法。下面 §三 横评用的 9 套权重全部是这个结构 - AlignNet(中):多一个 dataset embedding 通道拼进 decoder,学 domain-specific 的 bias/scale。推理时如果知道输入属于某个训练域可以指定 embedding;不知道就走 AlignNet 原论文的"reference dataset"启发式(选一个训练集当默认,比如 NISQA)
- Dataset embedding retrieval(右):SHEET 论文对 AlignNet 推理侧的改进------用测试样本的 SSL 表征去 datastore 做近邻检索,取最近邻训练样本的 dataset embedding 喂给 decoder。绕过"选 reference dataset"这个启发式
SSL-MOS+MDF (Multi-Domain Fine-tuning)不在这张图里------结构跟 SSL-MOS 一样,只是训练目标从单集扩到多集加权,跟 AlignNet 变体一起绑定 all7 pooling(不含 urgent2024)。SSL-MOS + WavLM-Large 单独绑定 all8 pooling(含 urgent2024),也是 HF 权重库里 all8 只有这一种架构的原因。
论文的实测数字说 AlignNet + retrieval 这套 domain-aware 组合没能稳定超过 直接 pooling:pooling 相当于隐式的 domain-agnostic regularization,多域数据本身把过拟合压住了。这就是为什么 SHEET 官方主推 all8 pooling + SSL-MOS-WavLM-Large 权重。
1.4 8 个训练集与天然适用场景
从论文 Table I(训练集详情)整理出来的核心信息:
| 训练集 | fs (kHz) | 语言 | 音频类型 | 规模(train+dev) | 天然适用 |
|---|---|---|---|---|---|
| BVCC | 16 | En | TTS / VC 合成 + clean speech | 4.9k + 1k | TTS/VC 合成质量对比 |
| SOMOS | 24 | En | TTS clean speech(多系统) | 14.1k + 3k | TTS clean 精细排名 |
| SingMOS | 16 | Ch/Ja | SVS / SVC 唱声 | 2.0k + 544 | 唱声合成 / 转换 |
| NISQA | 48 | En | 模拟失真 + 真实通话 + clean | 11.0k + 2.7k | VoIP 通话质量 |
| TMHINT-QI | 16 | Ch | 噪声 + 增强 + clean(中文短句) | 11.6k + 1.3k | 中文降噪 / 增强 |
| Tencent | 16 | Ch | 模拟失真 + clean | 10.4k + 1.2k | 中文合成 / 通话失真 |
| PSTN | 8 | En | 电话线路 + 模拟失真 | 52.8k + 5.9k | 电话质感 |
| URGENT2024-MOS | 8--48 | En | 混杂失真 + 增强 | 6.2k + 690 | 通用降噪 / 编解码 |
all8 pooling |
mix | mix | 全部 8 集混训 | ~113k + 16k | 官方默认推荐 · 未知域 fallback |
关键 pattern:训练集自带 domain bias ------PSTN 见的都是 8 kHz 电话,pstn 权重对干净朗读打分会挤在很窄的高分段(后面 §三 横评里 σ<0.08 就是这个原因);SingMOS 只见过唱声,对说话打分不知道校准到哪儿。选对训练集匹配你的输入域,比选大主干重要得多。
1.5 长音频处理
SSL 主干原则上接受任意长度输入,但实操里有两个坑:
- WavLM-Large / HuBERT-Large 在长音频(> 30 s)上显存吃紧,24 GB 显存卡跑一段 60 s 音频容易 OOM
- 极短音频(< 1 s)做完 pool 后 feature 太少,MOS 预测方差会明显变大
工程上常见处理是 patch 化 :切成 10 s / 30 s 无重叠段,各自过一遍模型,再对 patch 分数取 mean 或 median。SHEET 官方 predict.py 走的是直接送整段的路径,长音频要自己在上层切分(§2.4 会给一段最短实现)。
二、上手:装依赖到打分
2.1 装
本文横评没走 pip 安装,而是从 GitHub clone 一份 SHEET 源码(v0.2.5 tag),用 sys.path 把 sheet 包和 repo 顶层的 hubconf.py 加进 Python 搜索路径。理由:hubconf.Predictor 是 SHEET repo 顶层 hubconf.py 里的类,不在 sheet/ package 内------pip install sheet_sqa 完这文件也不会进 site-packages,只能靠 sys.path.insert 或走 torch.hub.load 的 cache 拿到。
# 实跑
git clone https://github.com/unilight/sheet.git third_party/sheet_repo
cd third_party/sheet_repo && git checkout main # v0.2.5 tag 的 hubconf.py 有一处漏逗号导致 SyntaxError · main 分支的 `6ce33c0 fix hubconf.py` 已修
# SHEET setup.cfg 里 install_requires 声明的:
# librosa>=0.8.0 · soundfile>=0.10.2 · pyyaml · h5py>=2.9.0 · filelock ·
# protobuf<=3.20.1 · scipy · s3prl · faiss-cpu
# 另外 torch / torchaudio / huggingface_hub 用户自己装
pip install librosa soundfile pyyaml h5py filelock 'protobuf<=3.20.1' \
scipy s3prl faiss-cpu \
torch torchaudio huggingface_hub
跑分脚本头部把 clone 出来的 repo 目录加进 sys.path:
# 实跑
import sys
from pathlib import Path
BLOG_ROOT = Path(".").resolve()
sys.path.insert(0, str(BLOG_ROOT / "third_party/sheet_repo")) # 装 sheet.models.sslmos 和顶层 hubconf.Predictor
sheet 包和 hubconf.py 都在 clone 出来的 repo 顶层(main 分支已修复 v0.2.5 tag 的 SyntaxError),一条 sys.path 全覆盖。SHEET 官方也支持 torch.hub.load("unilight/sheet", ..., trust_repo=True) 走 hub cache 路径------本文横评为了控制版本、避免 tag 撞坑,走显式 clone + sys.path。
首次运行会自动从 HF hub 下 config.yml + checkpoint-best.bin 到 ~/.cache/huggingface/hub/,主干(WavLM-Large / HuBERT-Large / wav2vec2-Large)走 s3prl 的 ~/.cache/s3prl/download/。
2.2 加载 & 打分:hf_hub_download + SSLMOS + Predictor 三件套
本文横评的实跑脚本走的是三件套:hf_hub_download 拉 config.yml + checkpoint-best.bin → 按 config 构造 sheet.models.sslmos.SSLMOS → hubconf.Predictor 包装做统一的 wav 读取和推理。
# 实跑(前面 2.1 的 sys.path 已经设好)
import yaml, torch
from huggingface_hub import hf_hub_download
def build_predictor(prefix: str):
"""Load SSLMOS from HF and wrap in Predictor from hubconf."""
cfg_path = hf_hub_download("unilight/sheet-models", filename=prefix + "/config.yml")
ckpt_path = hf_hub_download("unilight/sheet-models", filename=prefix + "/checkpoint-best.bin")
with open(cfg_path) as fh:
cfg = yaml.load(fh, Loader=yaml.Loader)
from sheet.models.sslmos import SSLMOS # local import after sys.path
m = SSLMOS(cfg["model_input"], **cfg["model_params"])
sd = torch.load(ckpt_path, map_location="cpu", weights_only=False)
if isinstance(sd, dict) and "model" in sd:
sd = sd["model"]
m.load_state_dict(sd)
m.eval().cuda()
from hubconf import Predictor # from third_party/sheet_repo
return Predictor(m, cfg)
prefix 就是权重在 https://huggingface.co/unilight/sheet-models 上的相对路径,恒为 <训练集>/<arch>-<backbone>/<seed> 三段------§3.1 表格列的 9 套横评权重都是这个格式。想核对当前加载到的到底是什么架构 / 主干,cfg["model_type"](SSLMOS)+ cfg["model_params"]["s3prl_name"](wavlm_large / hubert_large_ll60k / wav2vec2_large_ll60k)是唯一权威。
2.3 wav 预处理和调用
Predictor.predict() 只接受 16 kHz mono 一维 tensor 或本地路径(互斥,两个都给会报错)。横评走 tensor 路径,预处理是标准的三步------resample 到 16 kHz、downmix、峰值归一:
# 实跑
import torchaudio
def load_wav(path):
wav, sr = torchaudio.load(str(path))
if sr != 16000:
wav = torchaudio.transforms.Resample(sr, 16000)(wav)
if wav.dim() > 1:
wav = wav.mean(0)
peak = wav.abs().max()
if peak > 0:
wav = wav / peak * 0.95
return wav
wav = load_wav("/path/to/test.wav")
score = predictor.predict(wav=wav.cuda())
print(f"MOS: {score:.3f}")
传路径接口 predictor.predict(wav_path=...) 由 hubconf.read_wav 内部做 resample + downmix + padding(补足到 MIN_REQUIRED_WAV_LENGTH = 1040 采样,否则 SSL 主干因序列过短崩),对短音频更省心;tensor 接口的优势是自己控制预处理和 GPU 分配------横评走 tensor 接口就是这个原因。
2.4 长音频的 patch mean
Predictor.predict() 走整段前向,长音频(> 30 s)在大主干上容易显存吃紧。横评脚本用 10 s 无重叠段各自打分再取均值:
# 实跑
@torch.no_grad()
def score_one(predictor, wav, seg: int = 10 * 16000) -> float:
n = wav.shape[-1]
if n <= seg:
return float(predictor.predict(wav=wav.cuda()))
parts = [float(predictor.predict(wav=wav[i:i + seg].cuda()))
for i in range(0, n - seg + 1, seg)]
return sum(parts) / len(parts)
想更稳可以换 median 或改 30 s 窗口,本文横评没跑这两种变体,效果差异不评论。这段实现有个 caveat:无重叠切段 + 不补末尾,音频长度不是 10 s 整数倍时最后 <10 s 的尾巴会被丢弃(例如 25 s 音频只会打 2 段 = 20 s,末 5 s 不计入均值);本文横评语料段长基本在 8-16 s,最多丢一小段尾,不影响相对趋势。
三、9 套权重横评
SHEET 官方权重库 https://huggingface.co/unilight/sheet-models 一共 37 个 checkpoint 文件,分两批格式:9 个新 checkpoint-best.bin (seed=1337,段 2 全部是 sslmos-<backbone>,本文横评就是这 9 套)+ 28 个老 checkpoint-*steps.pkl (seed=2337 / 3337 / 4337,段 2 是 sslmos / sslmos+mdf / alignnet,跟旧 torch.hub.load("default") 那条 legacy 加载路径配对,本文没跑)。
- 新
.bin系列覆盖:8 个单数据集 + 1 套 all8 pooling(含 urgent2024) - 主干覆盖 wav2vec2-Large-LL60k / HuBERT-Large-LL60k / WavLM-Large
实验口径 :所有权重跑同一批 75 条 16 kHz mono 干净朗读音频(LibriSpeech test-clean 45 条主说话人 + 30 条备选说话人;备选说话人从 test-clean 里剪一批不同 utterance 出来,用于观察同数据集内说话人间的漂移),单 GPU 一次 forward,9 套权重打完全批用时分钟级。分数写进 scores/sheet-all_weights.csv,675 行,按 file, domain, weight_slug, mos 索引。这是同一批干净朗读语音上的相对差异,不代表 zero-shot benchmark 上的绝对能力排序------SHEET 论文 Table 4-6 提供了正式的 OOD 评测数字。
3.1 挑出来的 9 套权重
.bin 系列每套都是 seed=1337 的 SSL-MOS best,各训练集覆盖一个主干配置:
| 权重 slug | 训练域 | 主干 | HF 相对路径(prefix) |
|---|---|---|---|
| bvcc | TTS/VC 合成 · 2010s 主流数据 | WavLM-Large | bvcc/sslmos-wavlm_large/1337 |
| somos | TTS 合成(Speech Only) | HuBERT-Large-LL60k | somos/sslmos-hubert_large_ll60k/1337 |
| singmos | 唱声合成 SVS | wav2vec2-Large-LL60k | singmos/sslmos-wav2vec2_large_ll60k/1337 |
| nisqa | VoIP / 通话失真 | WavLM-Large | nisqa/sslmos-wavlm_large/1337 |
| tmhint-qi | 增强/降噪(中文短句) | wav2vec2-Large-LL60k | tmhint-qi/sslmos-wav2vec2_large_ll60k/1337 |
| tencent | 通话失真(中文) | wav2vec2-Large-LL60k | tencent/sslmos-wav2vec2_large_ll60k/1337 |
| pstn | 电话线路 | wav2vec2-Large-LL60k | pstn/sslmos-wav2vec2_large_ll60k/1337 |
| urgent2024 | 混杂噪声 + 混响 + 编解码 | WavLM-Large | urgent2024-mos/sslmos-wavlm_large/1337 |
| all8 pooling | 上面 8 个一起训 | WavLM-Large | bvcc+somos+singmos+nisqa+tmhint-qi+tencent+pstn+urgent2024-mos/sslmos-wavlm_large/1337 |
切权重 = 换 prefix 字符串 ------三件套接口不变,build_predictor(prefix) 直接返回新 predictor。
3.2 循环打 9 套权重的实跑代码
横评主循环的骨架,实际就是外层遍历 9 个 prefix、内层遍历 75 条 wav:
# 实跑
WEIGHTS = [
("bvcc", "bvcc/sslmos-wavlm_large/1337"),
("somos", "somos/sslmos-hubert_large_ll60k/1337"),
("singmos", "singmos/sslmos-wav2vec2_large_ll60k/1337"),
("nisqa", "nisqa/sslmos-wavlm_large/1337"),
("tmhint-qi", "tmhint-qi/sslmos-wav2vec2_large_ll60k/1337"),
("tencent", "tencent/sslmos-wav2vec2_large_ll60k/1337"),
("pstn", "pstn/sslmos-wav2vec2_large_ll60k/1337"),
("urgent2024", "urgent2024-mos/sslmos-wavlm_large/1337"),
("all8", "bvcc+somos+singmos+nisqa+tmhint-qi+tencent+pstn+urgent2024-mos/sslmos-wavlm_large/1337"),
]
for slug, prefix in WEIGHTS:
predictor = build_predictor(prefix)
for path, domain in items: # items: [(Path, domain), ...] 共 75 条
wav = load_wav(path)
mos = score_one(predictor, wav) # 内部走 patch mean(§2.4)
writer.writerow([path.name, domain, slug, f"{mos:.4f}"])
del predictor
torch.cuda.empty_cache() # 每套跑完释放主干,避免 3 种 SSL 主干同时驻留显存
三个实测坑:
- 每换一个 SSL 主干(wavlm_large / hubert_large_ll60k / wav2vec2_large_ll60k)都要多下一次对应的预训练权重------本次横评 3 种主干各下一次,磁盘占用 ~1 GB。只关心其中 1-2 套权重时只装对应主干即可
- 跨主干循环必须每套完了
del predictor + torch.cuda.empty_cache()------3 种 SSL 主干(含 WavLM-Large 316M)同时驻留显存很容易 OOM - HF 上还有 28 个
.pkl老格式 checkpoint 跟旧torch.hub.load("default")legacy 加载路径配对,不能用SSLMOS类直接装载(架构不同),本文横评没覆盖这批
3.3 测试语料
- LibriSpeech test-clean 主组 45 条:全部来自说话人 6930 · 干净朗读 · 单声道 16 kHz · Public Domain
- LibriSpeech test-clean 备选组 30 条 (下称
librispeech-alt):21 条来自另一说话人 1320 + 9 条仍来自 6930(chapter/utterance 跟主组无重叠)· 用来观察加入新说话人后 MOS 打分的偏移
共 75 条,全走同一段预处理(downmix + resample + peak norm),保证所有权重打分口径一致。原设计里还想放 VCTK 做多口音对比,2026 Q3 起 HuggingFace 上主流的 VCTK 加载脚本被 datasets 新版本废弃、Edinburgh 原始镜像 12 GB 不适合本次快速评测,暂时放弃这个变体;结论段会显式区分本 demo 语料下的相对差异与跨发布 benchmark 两个口径。
3.4 分数分布

三个观察值得单独拎出来:
- 权重之间存在 1.4 分的系统性偏移 ------同一批干净朗读语音,
somos均值 3.21、tmhint-qi均值 4.62,两者相差 1.40 MOS,几乎跨了一个 P.800 主观等级(Fair → Good)。跨权重比较绝对分毫无意义,业务侧要盯的是相对趋势(同权重下 A 版本 vs B 版本),不是绝对数字 - 三套权重逼近饱和 :
pstn(σ=0.054)、tmhint-qi(σ=0.073)、singmos(σ=0.077)在 LibriSpeech 上标准差 <0.08------训练分布只见通话线路(pstn)、增强/降噪场景(tmhint-qi)或唱声(singmos),遇到干净朗读时输出被聚在训练里对应的高分位段(均值分别在 4.20 / 4.62 / 4.46 附近),几乎给全批打同一个分,区分度接近零 - 加入新说话人会拉高均分 0.4 :
bvcc和nisqa在librispeech-alt30 条上的均值分别为 4.18 和 4.30,比主组的 3.77 / 3.89 高出 0.41 / 0.41。但分组内细看:librispeech-alt里那 9 条仍属主说话人 6930 的样本,均值分别是 3.92 / 3.67(跟主组接近),漂移几乎完全由 21 条新说话人 1320 的样本(均值 4.29 / 4.57)拉起来。换句话说这条差异是"新说话人 1320 被这两个权重打得更高",不是"任意换说话人都会漂"。而pstn/tmhint-qi/singmos因为已经饱和,反而看不到明显漂移------分不出来 不等于 稳定
3.5 权重之间的相关性

热力图里能读出三件事:
- 通话/失真类权重高度扎堆 :
pstn↔tencentρ=+0.78 ·nisqa↔tencentρ=+0.65 ·nisqa↔urgent2024ρ=+0.63------四套权重的训练数据里都含电话失真 / VoIP 编解码。但注意 :分说话人复算后nisqa↔urgent2024在 spk 1320 那 21 条上 ρ 掉到 -0.055,说明 pooled 相关性的相当一部分来自"混合说话人"这个结构性差异,不是"对通话质感的一致排序" - 合成/唱声类的三套彼此低相关 :
bvcc↔somosρ=+0.43 ·somos↔singmosρ=+0.24------SOMOS 训练的都是同语言不同 TTS 系统对比,SingMOS 训练的是 SVS 唱声,BVCC 是 VMC 官方混合训练集;三者面对同一批干净朗读,各自锚在不同的质量子空间里,排出来的顺序对不上 - all8 pooling 跟通话/失真类权重更贴近 :ρ(
all8,nisqa) = +0.80 · ρ(all8,pstn) = +0.80 · ρ(all8,tencent) = +0.76 · 但 ρ(all8,somos) = +0.45 · ρ(all8,tmhint-qi) = +0.43。分说话人复算all8↔pstn在 spk 1320 上 ρ = -0.147------同样有很大一部分被说话人结构撑起来。至于是不是 pooling 时通话/失真类样本量占大头把all8拉过去,本文没做训练采样消融,不下结论
⚠️ 双峰陷阱 :上面三行 ρ 全是在 75 条混合样本上算的,包含"主组 45 条 · 备选组 30 条"这个说话人双峰------bvcc / nisqa 两组间均值差 0.4 分,pstn / tmhint-qi / singmos 已饱和(σ<0.08)两组均值几乎重合,pooled ρ 因此普遍偏高,nisqa↔urgent2024 与 pstn/all8 一对分说话人复算后甚至翻符号。pooled ρ 只能说明权重对说话人分布差异读到的方向大体一致,说不上对某个质量因素排序一致------想下"合成派 vs 失真派"这类结论得叠训练分布消融 + 分层复算,本文没跑,不下。
3.6 选权重的经验规则
先把警戒写在前面:下面表格和三条建议是从上述 75 条干净朗读的分布观察外推出来的,不是场景选型结论------本文既没有主观 MOS 参考、也没做配对退化实验(同一段音频加不同强度失真的 A/B),SHEET 论文 §VI-A 里明确说过合成训练集并未普遍在合成测试集上占优。真要给业务选权重,请以论文 Table 4-6 的 zero-shot 结果、加你自己的 A/B 配对退化实验为准。
| 场景(仅参考) | 从本 demo 分布看更贴近的权重 | 本 demo 观察到的对应现象 |
|---|---|---|
| TTS / VC / SVS 合成质量 | bvcc / somos |
训练分布对齐 · 分布跟合成/唱声类扎堆低相关 |
| 通话/降噪/编解码 | pstn / nisqa / urgent2024 |
都在通话失真类紧密相关簇里 |
| 唱声 SVS 单独评估 | singmos |
独一份 SVS 训练集 · σ 极低 · 别期望强区分度 |
| 不确定域 / 快速筛选 | all8 pooling |
论文 recommend · 稳定但含偏 |
三条使用建议:
- 绝对分不可跨权重比 :报数字必带权重名------同样的 3.9 分,
bvcc的 3.9 跟all8的 3.9 业务含义完全不同 - 同权重 A/B 版本的相对趋势值得信 · 但需要 anchor :饱和权重(
pstn/tmhint-qi)在相同录音的前后对比上也能给出一致方向;前提是 A/B 音频的域与训练分布对齐,而且最好搭一批人工盲听 anchor 校准打分尺度------本 demo 只有跨说话人分布观察,不构成 A/B 可靠性证据 - 同方向偏移不能靠合投消除 :本 demo 里
bvcc和nisqa在加入说话人 1320 时同方向漂 +0.41 · +0.41 分,等权平均后仍差 +0.41------合投只能对冲相互独立的随机偏移,同方向的分布 shift 一起加权还是原样。多权重合投是否有稳定收益本文没验证,实际部署要看配对 A/B 结果
3.7 分布不匹配 → fine-tune 的入口
跑完 9 套权重发现全都不贴自己业务域,唯一的正路是拿自己的标注数据微调。SHEET repo egs/<dataset>/run.sh 已经把训练配方按 8 个训练集分好目录,直接照着最贴近自己域的那个 recipe 改数据 manifest 就能起步:
- 架构改动几乎为零 :SSL-MOS = SSL 主干 + 时间池化 + 一个
nn.Linearhead,egs/<dataset>/conf/*.yaml里换data:段指到自己的 wav + MOS 标注就行;backbone 用wavlm_large/hubert_large_ll60k/wav2vec2_large_ll60k三选一,跟 §4.1 表格里的 9 套权重同源 - 标注协议参考论文 §III:每条音频 ≥ 5 个 rater、按 1-5 打分、onboarding 用 rater 间一致性阈值(论文用 Pearson > 0.7 类似准则)筛人。业务侧做 in-house 标注按同一协议起步就够
- 数据规模:8 个训练集里最小的 SingMOS 只有 train 2.0k + dev 544(论文 Table I),量级参考------in-domain 几百到几千条本域样本通常就能显著改善 in-domain 相关性
- fine-tune 策略:主干全参 fine-tune 是标配,学习率给 head 大一档(1e-3 量级)、给 backbone 小一档(1e-5 量级)是 SSL-MOS 系列的常规做法;数据量少(< 1k)时可以冻结主干只训 head 起步
权重下载与推理脚本:见 https://huggingface.co/unilight/sheet-models 与 https://github.com/unilight/sheet 官方 README。本文没跑 fine-tune,具体流程按官方 README 走。