AI Pulse

百M参数开放权重模型,登顶VoiceArena说话人分割榜

百M参数开放权重模型,登顶VoiceArena说话人分割榜

为什么说话人分割(Speaker Diarization)很重要

每次对话都携带两层信息:说了什么,以及是谁说的。语音识别(ASR)负责捕捉并转录文字,而说话人分割负责对“谁在何时说话”进行分类,帮助应用把内容关联到正确的参与者。

想象一场会议、一通客服电话或一档播客的逐字稿:每句话都正确,但没有一句标注了说话人。你能读到文字,却无法可靠地判断是谁做出了承诺、谁提出了反对,或者哪个参与者打断了讨论。检索、摘要、行动项、对话分析和语音代理记忆都会因此变得不那么有用。

说话人分割会识别每个说话人活跃的时间区间,包括人们互相重叠说话的区间。这些说话人时间戳随后可以与自动语音识别(ASR)结合,生成一份带说话人属性的转录稿。

NVIDIA Nemotron 3 Diarization 是一个开放权重、100M 参数的模型,在 VoiceArena 的 Diarization-Bench 排行榜上以 14.72% 的分割错误率(DER)排名第一。它支持在直播和录音对话中识别最多八位说话人,能够处理重叠语音、分块处理不定长度的录音,并提供可定制的流式延迟。

更早的模型如 NVIDIA Streaming Sortformer 为四说话人分割确立了这一方法,包括下面用作基线的 streaming diar_streaming_sortformer_4spk-v2.1 检查点。Nemotron 3 Diarization 将支持扩展至八位说话人,并在下面评估中展现出更高的准确率和吞吐量。

Nemotron 3 Diarization 的工作原理

一个模型同时支持离线与流式对话

分割系统必须解决两个相关问题。首先,它必须检测语音并将其分配给正确的说话人。其次,它必须在整个对话过程中保持这种分配,即使在静默、打断或说话人间隔很久之后也是如此。

流式传输让第二个问题更难。离线模型可以一次性查看整个录音,而流式系统只收到一小块新音频和有限的上下文。如果没有有效的记忆机制,当前块中被分配到某个输出通道的说话人,在下一块中可能会被分配到另一个通道。

Nemotron 3 Diarization 遵循 Sortformer 的做法:按说话人首次出现的顺序对输出说话人进行排序。第一个新声音成为第一说话人通道,下一个新声音成为第二通道,以此类推。这种到达时间排序让模型的通用说话人标签保持稳定,也免去了为每个块重新求解说话人排列的需要。

Nemotron 3 Diarization 使用公开和授权语音数据训练,包括来自 David AI 授权的、带多说话人标注的真实世界对话。额外的 David AI 授权音频为覆盖 21 种语言的大规模模拟英语和多语言混合数据提供了素材。在训练中加入 David AI 数据后,离线式和超低延迟工作点的复合分割错误率(DER)降低了 0.77 个绝对百分点,从 11.19% 降至 10.42%。

该模型支持最多八个说话人通道。这些是匿名标签,而非真实世界身份:模型可以报告 speaker_2 在某个时间段内说话,但不会确定 speaker_2 就是某个特定的人。下游应用可以将这些匿名通道 ID 映射到明确的说话人身份,例如将时间戳与会议元数据、用户资料或活跃说话人验证模型配对。

从音频到说话人活动

模型接受 16 kHz 单声道音频,并将其转换为 10 ms 帧步长的梅尔频谱图特征。它将帧按 8 倍堆叠,生成 80 ms 帧,送入带旋转位置嵌入(RoPE)的 31 层 Transformer 编码器。在 Transformer 之上,一个 Conv1D 层将预测结果上采样回输入特征分辨率。默认输出是 [T, 8] 的浮点张量:T 个时间步乘以八个可能说话人通道。每个值代表该时间点上某个说话人活跃的概率。默认步长为 10 ms,也可以配置为 10 ms 的其他倍数。

这种表示天然能处理重叠:如果两个人同时说话,同一帧中可以有两个通道同时活跃。后处理会将这些概率转换为带开始和结束时间戳的通用说话人标签。

在流式推理过程中,两种记忆形式提供上下文:
- 到达顺序说话人缓存(AOSC)保留较早块中观察到的、按到达顺序通道组织的说话人信息。
- 先进先出(FIFO)队列在当前块之前提供最近的帧上下文。

输入缓冲区还包括右侧上下文,即当前块之后的音频。更多右侧上下文有助于模型理解说话人切换,而更少右侧上下文能减少产生结果所需的等待时间。当前块、右侧上下文、FIFO 队列和说话人缓存共同让一个模型能在多个延迟点工作。

分块推理消除了模型对最大音频时长的固定限制。对于异常长的录音、或存在严重噪声、混响、远场采集、域偏移的音频,性能仍可能下降。

Diarization 与带说话人属性的 ASR(多说话人 ASR)是不同任务

独立的 Diarization 产生说话人活动和时间戳,而不是所说的文字。ASR 产生文本,但不一定保留说话人归属。带说话人属性的转录流水线将两者结合:先由 Diarization 输出音频时间戳,再与 ASR 输出结合,把口语内容映射到具体说话人。

这种区分在系统设计时很重要。Diarization 错误包括漏检、误检、说话人分配错误和边界错误;ASR 错误则影响文字本身。应用应在目标音频上分别评估这两个组件以及组合后的流水线。

在延迟与精度之间取得平衡

同一个模型支持推荐输入缓冲区延迟为 30.4、1.04、0.64 和 0.32 秒。较短的缓冲区让系统更快响应,而更多上下文通常能提高准确率和吞吐量。这些值衡量的是推理前缓冲的音频;计算、网络、ASR 和应用处理会额外增加端到端延迟。虽然模型技术上可以使用 80 ms 输入缓冲区,但 0.32 秒是推荐的最低配置。下面的配置表展示了如何选择工作点。

基准测试结果:在 VoiceArena 初始 Diarization-Bench 中排名第一

在 VoiceArena 的初始 Diarization-Bench 结果中,NVIDIA Nemotron 3 Diarization 在 12 个系统、共 17 个系统配置中排名第一。评估覆盖 139 段英语对话,总时长约 22 小时。在对重叠语音计分、系统自动生成语音活动检测、且不使用边界 collar(boundary collar)的条件下,Nemotron 3 Diarization 达到了 14.72% 的分割错误率(DER),而排名第二的系统为 19.3%——相对降低了约 24%。此外,它在 100 ms 和 250 ms collar 下也位列第一,且在现场(in-person)和在线录音上均排名第一。这些初始结果可能会随着 VoiceArena 完成 Version 1 评估和配对统计分析而变化。

衡量说话人分割精度

评估该模型的主要指标是分割错误率(DER),它合并了三种错误:
- 漏检(Missed speech):参考说话人处于活跃状态,但系统未检测到相应语音。
- 误检(False alarm):系统标记某说话人活跃,但参考中没有对应语音。
- 说话人混淆(Speaker confusion):系统在正确时间检测到语音,但分配给了错误说话人。

DER 的计算是:将漏检、误检和说话人混淆相加,再除以参考说话人的总时长。重叠的参考说话人各自贡献到分母中。

基准设置会实质性地改变 DER,因此评估协议也是结果的一部分。Nemotron 3 评估包含 901 条特定条件下的录音,涵盖多语言电话语音、会议、近场与远场麦克风、多麦克风采集以及困难声学环境。每次评估都会对重叠语音计分。其中 DIHARD III、AliMeeting、AMI 和 NOTSOFAR1 使用零秒 collar,意味着没有边界容差被排除在计分之外;CALLHOME-Part2 使用 0.25 秒 collar。结果由 NeMo e2e_diarize_speech.py 评估脚本生成。

下面的对比使用 diar_streaming_sortformer_4spk-v2.1 作为基线,这是 NVIDIA 之前面向四说话人的流式 Sortformer。对比采用最终版 Nemotron-3-Diarization 的数值。

1.04 秒延迟下平均 DER 相对降低 40%

在 1.04 秒输入缓冲区延迟下,Nemotron 3 Diarization 在所有列出的八个条件上均降低了 DER。相对降幅从 CALLHOME-Part2 的 9.0% 到 NOTSOFAR1 MHM 的 65.2% 不等。八个数据集逐项相对降幅的未加权平均值为 41.0%。也就是说,这是各评估条件下相对改进的平均值,而不是把全部录音合并成一个分数后计算出的汇总 DER。

改进在各工作点上也是一致的。在两模型共有的每个延迟设置(30.4、1.04 和 0.32 秒)下,最终模型在每个数据集的完整 DER 都更低。

在说话人数量更多的情况下改进更大

八说话人支持让会议和小组讨论可以容纳四个以上参与者。在 DIHARD III、CALLHOME-Part2 和 NOTSOFAR1 的更高说话人数量子集上,基准优势也进一步扩大。图例也保留了一个重要细节:在 CALLHOME 的双说话人子集上,最终模型记录到 5.98% DER,而基线为 5.68%;但在完整 CALLHOME-Part2 评估中,DER 从 10.32% 改进到 9.10%,且更高说话人数量子集的增益更大。DIHARD III 将五到九位说话人的录音合并为一个结果。九位说话人超过了 Nemotron 3 Diarization 支持的八人上限,因此该聚合中包含超出指定说话人数限制的音频。

精度与吞吐量

一个可部署的 diarization 系统必须在精度和吞吐量之间取得平衡。模型卡报告实时因子加速(RTFx),计算方式是音频总时长除以处理总时长。RTFx 越高,说明系统在单位计算时间内处理的音频越多。在 30.4 秒配置下,Nemotron 3 Diarization 在 batch size 32 配合 torch.compile() 时达到 15,113× RTFx,基线为 2,619×,同时将 DIHARD III DER 从 19.09% 降至 12.73%。在 1.04 秒配置下,达到 865×(基线 136×),同时 DER 从 19.60% 降至 13.18%。

这些结果衡量的是公开测试系统上的批量吞吐量,不应解释为单流、端到端的应用延迟。开发者应在目标硬件上对完整流水线进行基准测试,包括数据搬运、分割、ASR 和下游处理。

体验 Nemotron 3 Diarization

你可以打开 Nemotron Diarization 实时模型演示,把模型输出的说话人时间戳与一段可跟随的对话对应起来。该应用提供合成对话、八说话人模式、实时麦克风输入和压力测试场景。我们还为多语言 ASR 模型增加了实时麦克风,因此可以对说不同语言的说话人执行实时流式分割。

从 Conversation 开始,选择一个预置话题,然后在对话播放过程中跟随说话人活动和实时转录。注意听打断,并把声音出现时间与显示的说话人活动对比。要使用自己的对话,请使用 Live Mic 或 Multilingual Live Mic。你也可以在 Audio File 标签中上传预先录制的音频文件。

下面这个杜撰的示例说明了说话人归属带来的差异;它不是演示的实测输出:

无说话人归属有说话人归属
"I'll send the report." "Can you include the figures?" "Yes, by Friday."speaker_0: "I'll send the report." speaker_1: "Can you include the figures?" speaker_0: "Yes, by Friday."

有了说话人标签,应用就能把承诺与回答后续问题的同一位参与者关联起来。时间线还能提供纯文本无法呈现的信息:两个说话人可以同时活跃。下游摘要器可以使用带归属的转录稿提取行动项,同时保留来源说话人和时间戳。

准备场景使用合成音频。部分八说话人场景在可听对话前提供了一段简短的说话人上下文 primer;它们演示的是有该上下文时的行为,不是无 primer 的基准测试。参与者姓名和角色属于应用的场景逻辑。Nemotron 3 Diarization 提供的是通用说话人通道和时间戳,而不是身份验证。

使用 NVIDIA NeMo Speech 快速上手

下面我们将展示几个快速上手指南:如何将 Diarization 与 ASR 模型、流式 ASR、仅 Diarization 以及离线 ASR 结合使用,借助 NVIDIA NeMo Speech 库实现。

安装依赖

在配置 Python 3.12 或更高版本、Cython 和较新的 PyTorch 版本后,安装系统包和 NVIDIA NeMo speech 依赖。

apt-get update && apt-get install -y libsndfile1 ffmpeg
uv pip install Cython packaging
uv pip install 'nemo-toolkit[asr]'

在真实场景中实现流式 Diarization + 流式 ASR(多说话人 ASR)

要评估 ASR 和 Diarization(多说话人 ASR)的性能,请参阅“流式 ASR 的 Diarization 快速上手指南”。

在录音上运行离线 Diarization

使用一段 16 kHz 单声道、包含两个以上说话人的录音,并将 /path/to/conversation.wav 替换为实际路径。下面的示例加载检查点,并使用推荐的 30.4 秒离线式配置。

from nemo.collections.asr.models import SortformerEncLabelModel

diar_model = SortformerEncLabelModel.from_pretrained(
    "nvidia/Nemotron-3-Diarization"
)
diar_model.eval()

# 配置值的单位是 80 ms 帧。
diar_model.sortformer_modules.spkcache_len = 264
diar_model.sortformer_modules.fifo_len = 40
diar_model.sortformer_modules.chunk_len = 340
diar_model.sortformer_modules.chunk_right_context = 40
diar_model.sortformer_modules.spkcache_update_period = 300
diar_model._check_streaming_parameters()

predicted_segments = diar_model.diarize(
    audio=["/path/to/conversation.wav"],
    batch_size=1,
)

for segment in predicted_segments[0]:
    print(segment)

diarize() 方法返回字符串形式的带说话人标记片段,格式为 start_seconds end_seconds speaker_id。例如,输出结构可能如下(时间戳仅作示意,并非模型实测结果):

0.400 2.100 speaker_0
1.800 3.250 speaker_1
3.600 4.700 speaker_0

这里两个说话人在 1.800 到 2.100 秒之间同时活跃。一个说话人可以出现在多个片段中,片段之间不需要互斥。若想同时得到底层的说话人活动张量,请设置 include_tensor_outputs=True

该 API 接受音频路径、路径列表、NumPy 数组或行分隔的 JSON manifest。传入 NumPy 数组时,请提供正确的整数 sample_rate;默认文件音频采样率为 16 kHz。Nemotron 3 Diarization 支持 16 kHz 单声道 .wav.flac.opus.mp3 音频。它面向 Linux 系统设计,支持 NVIDIA Ampere、Hopper 或 Blackwell GPU。

选择延迟-质量工作点

Nemotron 3 Diarization 以 80 ms 编码器帧为单位暴露流式参数。推荐配置覆盖从离线式处理到超低延迟流式的各种场景。

配置输入缓冲区延迟Speaker cacheFIFOChunkRight contextCache update period
Offline style30.4 s2644034040300
Low latency1.04 s26426494222
Very low latency0.64 s26426462222
Ultra-low latency0.32 s26426431222

表中的延迟值是输入缓冲区延迟,计算方式为 (CHUNK_LEN + RIGHT_CONTEXT) × 80 ms。它们不包含模型计算、网络传输、ASR 或应用处理。虽然模型技术上可以使用短至 80 ms 的输入缓冲区,但 0.32 秒是最低推荐配置。降低延迟通常会同时降低精度和吞吐量,因此开发者应根据端到端产品需求来选择工作点,而不是只看缓冲区时长。

在推理示例中,请使用同一行中的全部五个参数值,并在运行分割前调用 _check_streaming_parameters()。Speaker cache 保留早期说话人上下文;FIFO 控制近期历史;chunk 和 right context 决定输入缓冲区延迟;cache update period 控制一次缓存更新使用多少 FIFO 上下文。

将 Diarization 与离线 ASR 结合

在同一个录音和同一时间基准上运行 ASR 和 Diarization。例如,你可以用 Nemotron ASR 3.5 或 Parakeet TDT 0.6B v3 这类能返回词级别时间戳的模型。下面的最小离线示例复用上面的 predicted_segments,并将每个词关联到其时间中点处活跃的说话人:

from nemo.collections.asr.models import ASRModel

asr_model = ASRModel.from_pretrained(
    model_name="nvidia/parakeet-tdt-0.6b-v3"
)
words = asr_model.transcribe(
    ["/path/to/conversation.wav"], timestamps=True
)[0].timestamp["word"]

turns = []
for segment in predicted_segments[0]:
    start, end, speaker = segment.split()
    turns.append((float(start), float(end), speaker))

def speaker_at(midpoint):
    active = sorted({
        speaker for start, end, speaker in turns if start <= midpoint < end
    })
    if len(active) == 1:
        return active[0]
    return "overlap/ambiguous" if active else "unassigned"

for word in words:
    midpoint = (word["start"] + word["end"]) / 2
    label = speaker_at(midpoint)
    print(f"{word['start']:.2f}-{word['end']:.2f} {label}: {word['word']}")

这个中点规则是一种简单的对齐启发式方法。它会把同时说话人活动标记为 ambiguous,并把检测语音之外的词标为 unassigned。它无法分离重叠语音,也无法确定到底是哪个活跃说话人产出了某个 ASR 词。如果要用于生产环境转录,请先在代表性音频上评估词边界对齐、重叠处理和两个模型的错误,然后再把相邻词合并成说话人轮次。

部署注意事项

模型最多支持八个说话人。如果录音中包含更多说话人,语音可能漏检或被分配到错误通道。噪声、严重混响、远场录音、域偏移和长对话也会增加漏检、误检、边界错误或说话人混淆。下游应用应保留有用的不确定性,而不是把每次说话人分配都当作绝对正确。请在与目标环境足够接近的音频上评估完整系统,尤其在使用说话人归属用于受监管、安全相关或影响重大的流程之前。

使用该模型需遵守 OpenMDW 许可协议 1.1 版。

阅读原文
📚 相关主题 开源

订阅 AI Pulse

每天 08:00 · 12:30 · 18:30 · 23:50 更新