说话人分离和声纹识别,不是一回事
说话人分离(diarization)回答的是”谁在什么时候说话”,但它给出的只是匿名标签;声纹识别回答的是”这段声音是不是张三”,必须先注册后比对;语音分离则是把混在一起的多路声音拆成多条音轨,根本不在同一个层次上。
这三个词在中文里被混用得很厉害。最常见的误解是:以为上了说话人分离,系统就能认出会议里谁是谁了。事实不是这样。
先用一张表把三个词钉死
| 术语 | 英文 | 回答什么问题 | 需要预先注册吗 |
|---|---|---|---|
| 说话人分离 | speaker diarization | ”谁在什么时候说话”,把音频分成说话人1/2/3 | 不需要 |
| 说话人识别 / 声纹识别 | speaker recognition / verification | ”这段声音是不是张三” | 需要,先注册后比对 |
| 语音分离 | speech separation | 把混在一起的多路声音拆成多条音轨 | 不需要 |
这张表里最值得盯住的是最后一列。要不要预先注册,是区分前两者最硬的判据——它决定了你的产品要不要做一套采集、存储、管理声纹的流程,而这件事的工程量和合规成本,比接一个模型大得多。
说话人分离:它不知道谁是张三
diarization 做的事情是把一段连续音频按说话人切开并归组:这 12 秒是同一个人,那 30 秒是另一个人。
它的经典流程是:先分段(靠语音活动检测和说话人变更检测找边界)→ 对每一段提取说话人嵌入向量 → 把这些向量聚类 → 给每一类指派一个标签 → 再和识别结果按时间对齐。
注意最后指派标签这一步。聚类只能告诉你”这几段是同一个人”,没法告诉你这个人叫什么,所以标签只能是”说话人1""说话人2”这种序号。这些序号甚至没有跨文件的稳定性——同一个人在两场会议的录音里,很可能一次是说话人1,一次是说话人3。
分段这一步依赖的语音活动检测,就是 ASR 管道里常见的那个断句器,可以参考 VAD 是什么:ASR 前面为什么总要挂个断句器。
开源侧,pyannote.audio 自述为说话人分离的一组神经网络构件,包含语音活动检测、说话人变更检测、重叠语音检测和说话人嵌入;sherpa-onnx 的能力清单里也列了说话人分离。从构件划分就能看出,diarization 不是一个模型,而是一条小管道。
声纹识别:注册是绕不开的前提
声纹识别问的是另一个问题:这段声音属不属于某个已知身份。
它必须分两步走。注册:采集目标说话人的音频,提取嵌入向量存进库里。验证:把待测音频的嵌入和库里的向量算相似度,再和阈值比较。
任务形态有两种:1:1 验证(是不是本人)和 1:N 辨认(是库里的哪一个)。阈值调低,误识变多(把别人当成本人);调高,误拒变多(把本人拦在门外)。这个权衡必须按业务后果来定,不存在通用最优阈值——门禁和会议纪要贴名字,容错的方向完全相反。
还有一点要提醒:声纹是可以被录音重放攻击的,高安全场景需要额外的活体检测手段。别把一个为”贴标签”设计的模块直接搬去当身份凭证用。
注册与验证的完整流程见 声纹注册和验证是怎么回事。
开源侧,WeSpeaker 与 3D-Speaker 都自述为说话人验证、识别与分离的工具包,是这条线上常被提到的两个项目。
语音分离:这是信号层的事
语音分离和上面两个不在一个层次。它处理的是”两个人的声音混在同一条音轨里”这种物理叠加,输出是多条音轨,不是标签。
diarization 的输出是一份时间表,语音分离的输出是新的音频文件。前者是给内容打标注,后者是重新造信号。它们可以配合:真实会议里抢话很常见,而多数 diarization 的聚类隐含”同一时刻只有一个人”的假设,重叠段会被硬指派给其中一人,另一个人的话就直接丢了。这时候一条可选路径是先把重叠段用语音分离拆开,再分别送去识别。
重叠语音在工程上是被单独建模的子任务,具体见 两个人同时说话时会发生什么。
最关键的一句:匿名标签要变成真名,得再接一步
如果这篇只能记住一句话,就是这句:
diarization 给的是匿名标签,要变成真名,必须再接一步声纹比对。
具体做法是:拿到 diarization 分好的每一组音频,提取嵌入向量,去声纹库里检索最相似的注册人,相似度超过阈值就贴上真名,不超过就保留”说话人2”这个匿名标签。
很多人以为 diarization 直接就能认人,于是选型时只看分离效果,上线后才发现”名字对不上”,再回头补声纹库——注册流程、隐私告知、存储方案全都要重做。这一步该不该做,是产品需求决定的,不是模型能力决定的。会议纪要要不要显示真名,很多团队评估下来的答案其实是”不要”。
真实产品里,它们是怎么串起来的
以会议纪要为例,一条常见的链路是:
- VAD 切分:找出有人说话的片段,静音不必送模型。
- diarization 分匿名说话人:给每一段贴上说话人1、说话人2。
- 可选的声纹比对:有注册库就贴真名,没有就留着序号。
- ASR 转写:把音频变成文字。
- 按时间对齐:把说话人标签和带时间戳的文字拼在一起。
第 2 步和第 4 步的先后有两种做法。先分离再识别,每个说话人的音频单独送 ASR,声学环境更一致,但分离的边界误差会传导下去。先识别再对齐,先拿到带时间戳的完整转写,再按 diarization 的时间段贴标签,实现更简单,是工业上常见的做法。两种顺序的难点都在边界:一句话的头尾到底算谁的,都可能错。
在工具包层面,这几件事往往被打包在一条 pipeline 里,而不是各自独立部署。整条 ASR 管道的分工,可以参考 语音识别是怎么工作的:从声波到文字的四个环节。
为什么”说话人分离”这个译名本身就容易混
回头看这三个词,混淆其实有一半是翻译造成的。
speaker diarization 的字面意思接近”按说话人做日志标注”,中文却译成了”说话人分离”;而 speech separation 译成”语音分离”。两个译名都带”分离”,但一个分的是标签,一个分的是音轨。加上 speaker recognition 常被叫作”声纹识别”,“识别”二字又和 speech recognition(语音识别)撞车,四个概念在中文里挤成一团。
实用的办法是:在技术讨论里直接用英文原词,或者说清楚”回答的是哪个问题”。说”我要 diarization”比说”我要说话人分离”歧义少得多;说”我要知道每句话是谁说的,不需要知道他叫什么”,比任何术语都准确。
常见问题
问:只用声纹识别,能不能替代 diarization?
不能,两者的输入假设不同。声纹识别处理的是”一段已经切好的、只有一个人说话的音频”,而 diarization 要解决的恰恰是”怎么把连续音频切成这样的段”。没有前面的分段和聚类,声纹模块拿到的是一段多人混说的音频,比对结果没有意义。
问:不做声纹注册,能不能让说话人标签在多次会议之间保持一致?
做不到。聚类是在单次音频内部完成的,标签的序号只是聚类结果的编号,跨文件没有任何约束。想要跨会议稳定的身份,就得有一个持久化的向量库,那本质上已经是声纹注册了。
问:diarization 需要事先知道会议里有几个人吗?
不一定,但知道会更稳。人数已知时可以直接指定聚类数;人数未知时要靠算法自己估计,这一步在人数多、每人说话时长悬殊、或者有大量简短应答的会议里最容易出错。产品设计上,如果能让用户填个大致人数,通常比让算法猜要可靠。
相关阅读
本文讲的是说话人处理领域的通用概念辨析,不绑定某一个具体实现。 文中提到的开源项目,其能力描述取自各自仓库的公开自述,功能边界与实际表现请以官方文档为准。 我们没有对文中提到的任何方案做过效果实测,因此不给准确率、等错误率一类的数字。