声纹识别技术实践:AI 如何通过几秒钟的声音判断是不是同一个人?

举报
yd_54922183 发表于 2026/11/01 03:49:31 2026/11/01
【摘要】 本文介绍声纹识别的核心原理,并以开源 SpeechBrain ECAPA-TDNN 模型为例,通过双录音身份核验、多人声纹库匹配两个 Python 案例,展示如何构建一个本地声纹识别系统。

摘要: 人的声音和指纹一样,具有一定的个体差异。声纹识别(Speaker Recognition)就是利用这些差异,从语音中提取说话人特征,判断两段录音是否来自同一个人,或者从已注册人员中寻找最匹配的说话人。本文介绍声纹识别的核心原理,并以开源 SpeechBrain ECAPA-TDNN 模型为例,通过双录音身份核验、多人声纹库匹配两个 Python 案例,展示如何构建一个本地声纹识别系统。

一、声音也能识别一个人的身份?

假设有人给我们打电话。

电话接通后,对方只说了一句:

你好,我想咨询一下我的订单。

即使对方没有自报姓名,我们也可能凭借声音判断出他是谁。

这是因为不同人的声音存在一定差异,包括音色、共振特征、发声习惯等。

声纹识别试图让机器学习这些差异。

但这里有个很有意思的问题:

如果同一个人第一次说中文,第二次说英文,AI 还能判断出这是同一个人吗?

理论上可以。

因为声纹模型主要学习说话人的声学特征,而不只是识别具体说了哪些文字。

不过,跨语言、跨设备、跨环境的声纹匹配通常更困难,需要实际数据验证。

1.1 与 ASR、Diarization 的区别

此前我们研究过 ASR 和说话人分离(Diarization),现在可以把它们放在一起比较:

模型 核心问题 输出
ASR 说了什么? 转写文字
VAD 什么时候有人说话? 语音时间段
Diarization 一段录音中有几个不同的人? 匿名说话人标签
Speaker Verification 两段声音是否来自同一个人? 相似度与判断
Speaker Identification 这段声音最接近已注册的哪个人? 候选身份

其中,声纹识别又分为两个典型任务。

1:1 验证(Verification)

给定两段录音,判断是否来自同一个说话人。

1:N 辨识(Identification)

给定一段新录音,与声纹库中的 N 个候选人比较,找出最相似的人。

这两种任务使用的底层模型通常可以相同,只是后续匹配方法不同。

二、声纹识别模型的核心原理

现代声纹识别通常使用 Speaker Embeddings。

它与文本 Embeddings 非常相似,只是输入从文字变成了声音。

原始录音
   │
   ▼
音频预处理
   │
   ▼
声学特征提取
   │
   ▼
Speaker Encoder
   │
   ▼
声纹向量
   │
   ▼
余弦相似度计算
   │
   ▼
同一人 / 不同人

例如,两段录音被编码为:

[
v_1=f(audio_1)
]

[
v_2=f(audio_2)
]

再计算余弦相似度:

[
sim(v_1,v_2)=
\frac{v_1\cdot v_2}{|v_1||v_2|}
]

相似度越高,说明模型认为两段录音中的声学特征越接近。

但要注意:声纹相似度不等于身份匹配的真实概率。

例如,相似度 0.85,并不意味着有 85% 的概率来自同一个人。

2.1 典型开源模型

模型 特点 适用场景
ECAPA-TDNN 经典声纹模型,精度较好、参数量较小 声纹验证、身份匹配
ResNet34 Speaker Encoder 使用残差网络提取声学特征 声纹识别、声纹聚类
CAM++ 轻量级说话人表示模型 中文语音、实时应用
ERes2Net 多尺度声学特征建模 复杂录音环境
ReDimNet 面向效率与精度的声纹网络 低延迟声纹识别

本文选用:

SpeechBrain ECAPA-TDNN

对应模型:

speechbrain/spkrec-ecapa-voxceleb

主要特点:

  • 模型权重约 90MB。
  • 输出 192 维 Speaker Embeddings。
  • 支持 CPU 和 GPU 推理。
  • 使用 VoxCeleb1、VoxCeleb2 数据训练。
  • 模型许可为 Apache 2.0。

在官方 VoxCeleb1 Cleaned 测试集上,报告的 EER 为 0.80%。

EER 是等错误率,越低越好。这个结果属于指定测试集上的实验成绩,不能直接推广到中文电话录音或其他场景。

该模型主要采用英语语音数据训练,跨语言匹配可以作为实验方向,但需要额外验证。

相关开源项目:

如果业务以中文语音为主,还可以对比 WeSpeaker 提供的中文预训练模型。


三、实践案例一:判断两段录音是否来自同一个人

3.1 业务场景

假设我们有两段录音:

speaker_zh.wav  # 某人用中文说话
speaker_en.wav  # 某人用英文说话

我们希望判断它们是否来自同一个人。

这可以用于研究跨语言说话人匹配,也可以作为声纹验证系统的基础实验。

3.2 环境准备

建议使用 Python 3.10 或更新版本。

安装与运行环境兼容的 PyTorch、Torchaudio,然后执行:

pip install -U speechbrain soundfile

首次运行会下载模型权重,之后可以使用本地缓存进行离线推理。

建议先把两段录音统一转换为 16kHz 单声道 WAV。

ffmpeg -i speaker_zh.mp3 -ar 16000 -ac 1 speaker_zh.wav

ffmpeg -i speaker_en.mp3 -ar 16000 -ac 1 speaker_en.wav

3.3 Python 完整实现

import torch
from speechbrain.inference.speaker import SpeakerRecognition

# 1. 加载预训练声纹模型
device = "cuda" if torch.cuda.is_available() else "cpu"

model = SpeakerRecognition.from_hparams(
    source="speechbrain/spkrec-ecapa-voxceleb",
    savedir="pretrained_models/ecapa",
    run_opts={"device": device}
)

# 2. 两段录音
audio1 = "speaker_zh.wav"
audio2 = "speaker_en.wav"

# 3. 执行1:1声纹验证
score, prediction = model.verify_files(
    audio1,
    audio2
)

# 4. 获取相似度与判断结果
similarity = float(score.item())
same_speaker = bool(prediction.item())

print(f"声纹相似度:{similarity:.4f}")

if same_speaker:
    print("模型判断:可能是同一个人")
else:
    print("模型判断:可能是不同的人")

这里的 verify_files() 是 SpeechBrain 官方提供的接口。

它会自动提取两段语音的声纹向量,并计算相似度。

需要注意,官方接口默认采用 0.25 作为余弦相似度决策阈值。这是接口的默认设置,正式应用时应根据业务录音重新确定阈值。

3.4 如何解读结果?

假设得到:

声纹相似度:0.82
模型判断:可能是同一个人

以上是演示结果,不是实际模型运行结果。

这里的 0.82 是两段声音特征向量的相似度。

如果我们换成另一位说话人的录音,相似度可能明显下降。

不过,影响声纹匹配的因素有很多:

  • 麦克风及录音设备。
  • 背景噪声。
  • 录音时长。
  • 说话语速与情绪。
  • 不同语言的发音习惯。

因此,一段安静环境录制的中文音频,与同一个人在嘈杂环境中的英文录音,仍然可能出现较低的相似度。

这也是实际部署时必须进行场景验证的原因。


四、实践案例二:建立一个多人声纹库

第一个案例只是两段录音之间的比较。

但实际业务中,我们通常希望系统具备这样的能力:

新来一段录音,能否从已经注册的人员中找到最接近的说话人?

例如,一个经过授权的企业会议系统,已经保存了三名参与者的参考录音。

当新的语音片段进入系统时,我们希望找到最相似的已注册人员。

4.1 核心架构

人员A参考录音 ──> 声纹向量A ──┐
                             │
人员B参考录音 ──> 声纹向量B ──┼──> 声纹库
                             │
人员C参考录音 ──> 声纹向量C ──┘
                                   │
新录音                             │
   │                               │
   ▼                               │
ECAPA-TDNN                         │
   │                               │
   ▼                               │
新声纹向量 ────────────────────────┘
   │
   ▼
计算余弦相似度
   │
   ▼
寻找最相似的候选人
   │
   ▼
阈值判断 / 未知说话人

对于每个人,我们可以保存多段参考录音,再对声纹向量进行平均,形成一个更加稳定的声纹模板。

4.2 Python 实现

准备文件:

voices/
├── person_a_1.wav
├── person_a_2.wav
├── person_b_1.wav
├── person_b_2.wav
├── person_c_1.wav
├── person_c_2.wav
└── incoming.wav

所有录音建议统一为 16kHz 单声道 WAV,且每个文件尽量只包含一名说话人。

使用以下代码:

import numpy as np
import torch
from speechbrain.inference.speaker import SpeakerRecognition

# 1. 加载模型
device = "cuda" if torch.cuda.is_available() else "cpu"

model = SpeakerRecognition.from_hparams(
    source="speechbrain/spkrec-ecapa-voxceleb",
    savedir="pretrained_models/ecapa",
    run_opts={"device": device}
)

# 2. 提取声纹向量
def get_embedding(audio_path):

    # 官方加载方法,自动处理采样率等
    signal = model.load_audio(audio_path)

    with torch.no_grad():
        embedding = model.encode_batch(
            signal.unsqueeze(0)
        )

    vector = embedding.squeeze().cpu().numpy()

    # L2归一化
    vector = vector / (
        np.linalg.norm(vector) + 1e-12
    )

    return vector


# 3. 注册声纹
enrollment = {
    "person_A": [
        "voices/person_a_1.wav",
        "voices/person_a_2.wav"
    ],
    "person_B": [
        "voices/person_b_1.wav",
        "voices/person_b_2.wav"
    ],
    "person_C": [
        "voices/person_c_1.wav",
        "voices/person_c_2.wav"
    ]
}

speaker_database = {}

for name, files in enrollment.items():

    # 提取同一人的多段声纹
    embeddings = [
        get_embedding(path)
        for path in files
    ]

    # 计算平均声纹模板
    template = np.mean(embeddings, axis=0)

    template = template / (
        np.linalg.norm(template) + 1e-12
    )

    speaker_database[name] = template


# 4. 识别新录音
query = get_embedding("voices/incoming.wav")

# 5. 与声纹库逐一比较
scores = {}

for name, template in speaker_database.items():

    scores[name] = float(
        np.dot(query, template)
    )

# 6. 相似度排序
ranking = sorted(
    scores.items(),
    key=lambda x: x[1],
    reverse=True
)

for name, score in ranking:
    print(f"{name}: {score:.4f}")

# 7. 加入未知说话人拒识
best_name, best_score = ranking[0]

# 仅为实验阈值,正式使用需校准
threshold = 0.55

if best_score >= threshold:
    print("最相似的已注册人员:", best_name)
else:
    print("未知说话人,需要进一步核验")

4.3 这个案例有什么价值?

这里有两个值得关注的地方。

第一,声纹可以预先计算。

和文本 Embeddings 一样,已经注册的声纹可以提前保存。

新录音到来时,只需提取一次声纹向量,再与已有模板比较。

对于几十人、几百人的小规模声纹库,直接使用 NumPy 就可以完成匹配。

第二,可以支持未知说话人。

如果系统每次都强制从已注册人员中选择一个人,那么即使是一名陌生人,也会得到某个匹配结果。

因此,需要设置拒识阈值。

但代码中的 0.55 只是实验值。由于这里采用了多录音平均模板,其评分分布可能与官方 verify_files() 的评分分布不同,不能直接套用同一阈值。

对于规模更大的声纹库,还可以使用 FAISS 等向量检索工具加速候选搜索。


五、声纹识别实际部署有哪些难点?

5.1 阈值怎么确定?

声纹系统通常存在两类错误:

FAR(False Acceptance Rate):误接受率。

把不同的人错误识别为同一个人。

FRR(False Rejection Rate):误拒绝率。

把同一个人的两段录音错误识别为不同的人。

提高相似度阈值,通常会降低 FAR,但可能提高 FRR。

反过来,降低阈值会减少部分误拒绝,却可能增加冒认成功的风险。

因此,应当准备两类测试数据:

正样本:
同一个人的不同录音

负样本:
不同人的录音组合

然后分别计算不同阈值下的 FAR 和 FRR。

当两者相等时,对应的错误率称为 EER(Equal Error Rate)。

对于身份核验场景,实际阈值还应根据误接受和误拒绝的业务成本选择,不一定采用 EER 对应的阈值。

5.2 声音克隆会不会骗过声纹模型?

这可能是当前声纹识别最值得关注的问题。

此前我们介绍过 Qwen3-TTS,它可以使用少量参考录音复刻一个人的音色。

那么,如果攻击者生成一段高度相似的合成语音,再交给声纹识别模型,会发生什么?

部分声纹模型确实可能受到语音合成、声音转换及录音重放攻击的影响。

这是因为传统声纹模型主要判断声音的特征是否接近,而声音是不是由真人实时发出,属于另一个任务。

因此,在涉及身份认证的系统中,通常还需要额外增加:

  • 录音重放与合成语音检测。
  • 活体检测或随机口令挑战。
  • 其他身份认证因素。
  • 设备和异常行为风险检查。

例如,开源的 AASIST 就是专门研究语音反欺骗检测的模型。

但反欺骗模型也会存在误判和对新型伪造手段泛化不足的问题,因此声纹更适合成为多因素认证的一部分。

5.3 中文与英文混合会影响识别吗?

会有可能。

例如,同一个人在说普通话、英语和某些方言时,发声习惯、音素分布和语速可能发生变化。

因此,如果目标是中文客服或跨语言应用,可以同时测试:

测试组合 目的
中文 vs 中文 中文同语言识别
英文 vs 英文 英文同语言识别
中文 vs 英文 跨语言识别
不同设备录音 跨设备稳健性
安静 vs 嘈杂 抗噪声能力

对于以中文为主的业务,还建议额外对比 WeSpeaker 的中文声纹模型。

WeSpeaker 官方支持加载中文预训练模型,并提供 compute_similarity()、register() 和 recognize() 等接口。


六、总结:声纹识别在语音 AI 系统中的位置

本文通过两个案例介绍了声纹识别的核心能力:

  1. 双录音身份核验: 提取两段录音的 Speaker Embeddings,判断是否可能来自同一个人。
  2. 多人声纹库匹配: 为已注册人员建立声纹模板,对新录音进行相似度排序和未知人员拒识。

把它与之前的 VAD、ASR 和 Diarization 结合,可以得到一条更完整的语音处理链路:

             原始录音
                │
                ▼
            VAD 语音检测
                │
                ▼
       Diarization 说话人分离
                │
         ┌──────┴──────┐
         ▼             ▼
       ASR          声纹识别
         │             │
         ▼             ▼
      转写文本       候选身份
         │             │
         └──────┬──────┘
                ▼
       带说话人信息的记录
                │
                ▼
          LLM / 业务系统

例如,企业会议系统可以先通过 Diarization 区分发言者,再使用事先获得授权的声纹模板,将匿名说话人对应到参会人员,最后用 ASR 生成带发言人标签的会议纪要。

需要留意的是,声纹向量具有生物识别属性,应当妥善保存、限制访问,并在注册前取得相应授权。

最后,用一句话总结这几类模型的区别:

ASR 关注说了什么,Diarization 关注哪些片段属于同一个人,声纹识别则进一步判断声音是否匹配某个已知说话人。

随着 TTS 和声音克隆技术越来越成熟,声纹模型依然具有很高的应用价值,但仅靠“声音听起来像”,已经不足以完成可靠的身份认证。

真正值得研究的下一步,是将 声纹识别、语音反欺骗检测与多因素身份核验 结合起来,构建更可靠的语音身份识别系统。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。