- 人工智能
- 语音
- 音频
【免费下载链接】PaddleSpeech
Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.
导读
本文以 PaddleSpeech 仓库中examples/voxceleb/示例为主线,系统讲解如何在 VoxCeleb1/VoxCeleb2 大规模说话人数据集上完成声纹识别(Speaker Verification / Speaker Identification)任务的完整链路:从 m4a 音频格式转换、manifest 与 CSV 数据整理,到 ECAPA-TDNN 声纹骨干网络的训练、余弦相似度打分与 EER 评测,以及预训练模型的使用。读完本文,你将掌握 VoxCeleb 数据集的标准化准备流程、run.sh分段执行机制、ecapa_tdnn.yaml全量配置参数含义,并能独立复现一个可用于说话人验证的 ECAPA-TDNN 系统。
一、VoxCeleb 示例总览:sv0 与 sv1 两条技术路线
PaddleSpeech 的examples/voxceleb/目录围绕 VoxCeleb 数据集提供声纹识别参考实现,并拆分为两个子示例:
- sv0(纯 Python 实现):采用 softmax 分类后端(配合 Additive Angular Margin 损失)进行说话人识别训练,验证阶段使用余弦相似度打分。全部流程均为 Python 代码,不依赖 Kaldi,易于安装复现,详细说明见 sv0/README.md。
- sv1(依赖 Kaldi):说话人验证后端基于 PLDA / score normalization(sc)实现,训练与打分流程依赖 Kaldi 工具链,适用于追求更强打分策略的场景。
从仓库源码看,sv0 是当前维护最完整的路线:它包含完整的数据处理脚本、训练/测试脚本、两套 YAML 配置和结果记录(RESULT.md)。本文后续内容以 sv0 为核心展开。
二、VoxCeleb 数据集概览
VoxCeleb 系列是声纹识别领域广泛使用的真实场景说话人数据集,语音采集自 YouTube 视频访谈等自然环境,包含大量背景噪声、笑声、重叠说话、不同信道与口音,非常考验声纹模型的泛化能力。examples/voxceleb/README.md给出了四个数据划分的规模统计:
| 数据集 | Vox1 - dev | Vox1 - test | Vox2 - dev | Vox2 - test |
|---|---|---|---|---|
| 说话人数(spks) | 1211 | 40 | 5994 | 118 |
| 语音条数(utts) | 148642 | 4874 | 1092009 | 36273 |
| 时长(time, h) | 340.4 | 11.2 | 2360.2 | 79.9 |
可以看到,VoxCeleb2 的规模约为 VoxCeleb1 的 7 倍,dev 集合计覆盖 7205 个说话人(1211 + 5994),这正是 ecapa_tdnn.yaml 中num_speakers: 7205的由来——用 Vox1+Vox2 联合训练时分类头的类别数就是 7205。
三、VoxCeleb2 数据准备:m4a 转 wav
VoxCeleb2 的音频文件以 m4a 格式发布,而 PaddleSpeech 的音频前端统一按 wav 处理,因此在使用前必须将全部 m4a 文件转换为 16kHz 单声道 wav。examples/voxceleb/README.md给出了推荐的转换命令:
ffmpeg -y -i %s -ac 1 -vn -acodec pcm_s16le -ar 16000 %s参数含义:-ac 1强制单声道,-vn丢弃视频流,-acodec pcm_s16le指定 16bit PCM 编码,-ar 16000统一重采样到 16kHz。这一步耗时数小时,且只需执行一次。
仓库内 local/convert.sh 提供了一个 32 路并行的批量转换实现(信号量并发控制),实际执行的 ffmpeg 命令为:
ffmpeg -loglevel panic -i "$f" -ar 16000 "${f%.*}.wav"转换完成后,将所有 wav 文件放入名为wav的目录,目录结构应符合如下约定(data.sh与voxceleb2.py的 manifest 生成逻辑依赖该结构):
voxceleb2/wav/id*/<视频ID>/*.wav # 例如 voxceleb2/wav/id00012/21Uxsk56VDQ/00001.wav注意:convert.sh只做-ar 16000重采样,而 README 给出的通用命令还包含单声道与 PCM 编码参数,两者配合使用可保证 wav 与后续 fbank 特征提取(sr: 16000)完全对齐。
四、评测协议(trial)概览
说话人验证评测需要预定义的 trial 文件:每一行是一个"说话人对 + 标签"(1 表示同一说话人,0 表示不同说话人),模型对所有 trial 打分后计算等错误率(EER)。examples/voxceleb/README.md总结了 VoxCeleb 官方与清理版(cleaned)评测协议:
| Trial | 文件名 | 数量 | 正样本 | 负样本 |
|---|---|---|---|---|
| VoxCeleb1 | veri_test.txt | 37720 | 18860 | 18860 |
| VoxCeleb1 (cleaned) | veri_test2.txt | 37611 | 18802 | 18809 |
| VoxCeleb1-H | list_test_hard.txt | 552536 | 276270 | 276266 |
| VoxCeleb1-H (cleaned) | list_test_hard2.txt | 550894 | 275488 | 275406 |
| VoxCeleb1-E | list_test_all.txt | 581480 | 290743 | 290737 |
| VoxCeleb1-E (cleaned) | list_test_all2.txt | 579818 | 289921 | 289897 |
其中 VoxCeleb1-E 与 VoxCeleb1-H 分别是扩展与困难评测协议(官方数据划分),清理版剔除了与训练集说话人重叠的样本。sv0 的配置默认使用verification_file: data/vox1/veri_test2.txt,即 VoxCeleb1 cleaned 协议;这些 trial 文件会在数据处理阶段由 voxceleb1.py 自动下载并写入data/vox1/目录。
五、ECAPA-TDNN 示例(sv0)概览
sv0 的核心入口是 run.sh,它通过stage与stop_stage控制流水线执行范围,共分为三个阶段:
| Stage | 功能 |
|---|---|
| 0 | 数据处理:下载 VoxCeleb1、下载 VoxCeleb2、m4a 转 wav、生成 train/dev/test manifest、下载 RIR Noise 并生成增强用噪声 manifest |
| 1 | 训练声纹识别模型(说话人分类任务) |
| 2 | 使用余弦相似度对 VoxCeleb trial 打分并评测 |
只运行 stage 1 和 stage 2:
bash run.sh --stage 1 --stop_stage 2只运行单个 stage(例如仅处理数据):
bash run.sh --stage 0 --stop_stage 0从 run.sh 源码可以看到,该脚本同时支持通过--gpus、--dir、--exp_dir、--conf_path等命令行参数覆盖默认局部变量,例如指定 GPU:
bash run.sh --gpus 0,1若将gpus置空(gpus=),则完全使用 CPU 执行。
六、环境准备:path.sh 与 parse_options.sh
任何脚本运行前都需要先加载 path.sh 设置环境变量:
source path.sh其关键作用是:将MAIN_ROOT指向 PaddleSpeech 仓库根目录(realpath ${PWD}/../../../),把MAIN_ROOT与MAIN_ROOT/utils加入PATH,并设置PYTHONPATH,从而可以直接调用仓库内的train.py/test.py等模块。此外BIN_DIR被设置为${MAIN_ROOT}/paddlespeech/vector/exps/ecapa_tdnn,即声纹模型训练脚本所在目录。
run.sh内还会 source 仓库通用的参数解析脚本:
source ${MAIN_ROOT}/utils/parse_options.sh它实现了--variable value风格的命令行参数解析,这是整个 PaddleSpeech 示例体系统一采用的脚本参数约定。
局部变量说明
| 变量 | 含义 | 默认值 |
|---|---|---|
gpus | 使用的 GPU 编号,置空表示仅用 CPU | 0,1,2,3 |
stage | 起始阶段编号 | 0 |
stop_stage | 结束阶段编号 | 50 |
dir | 数据信息(manifest/csv/meta)存放目录 | data/ |
exp_dir | 实验输出目录(checkpoint 等) | exp/ecapa-tdnn-vox12-big/ |
conf_path | 模型配置文件路径 | conf/ecapa_tdnn.yaml |
七、Stage 0:数据处理详解
数据处理由 local/data.sh 完成,内部又细分为 8 个子阶段(stage 1–8),每个子阶段对应独立的 Python 脚本调用:
| 子阶段 | 动作 | 调用脚本 |
|---|---|---|
| 1 | 下载 VoxCeleb1 并生成manifest.dev/manifest.test及 meta、trial 文件 | voxceleb1.py |
| 2 | 下载 VoxCeleb2(m4a 压缩包) | voxceleb2.py |
| 3 | 将 VoxCeleb2 的 m4a 批量转为 wav | convert.sh |
| 4 | 扫描 wav 目录生成manifest.vox2 | voxceleb2.py |
| 5 | 将 manifest(json 格式)转为训练所需 CSV,并切分 train/dev/enroll/test | make_vox_csv_dataset_from_json.py |
| 6 | 下载 RIR Noise 数据集并生成 manifest | rir_noise.py |
| 7 | 生成噪声增强用 CSV | make_rirs_noise_csv_dataset_from_json.py |
两个下载脚本均以${MAIN_ROOT}/dataset为TARGET_DIR,即原始音频存放在dataset/voxceleb/vox1/{dev,test}与dataset/voxceleb/vox2/;而 manifest 与 CSV 等轻量索引文件写入dir(默认data/)。这也解释了examples/voxceleb/README.md中"VoxCeleb2 的 wav 需自行转换后放入wav目录"的原因——转换逻辑由 convert.sh 负责,训练脚本只消费 wav 索引。
数据处理完成后,data/目录结构如下(与 sv0/README.md 描述一致):
data/ ├── rir_noise │ ├── csv │ │ ├── noise.csv │ │ └── rir.csv │ ├── manifest.pointsource_noises │ ├── manifest.real_rirs_isotropic_noises │ └── manifest.simulated_rirs ├── vox │ ├── csv │ │ ├── dev.csv │ │ ├── enroll.csv │ │ ├── test.csv │ │ └── train.csv │ └── meta │ └── label2id.txt └── vox1 ├── list_test_all2.txt ├── list_test_all.txt ├── list_test_hard2.txt ├── list_test_hard.txt ├── manifest.dev ├── manifest.test ├── veri_test2.txt ├── veri_test.txt ├── voxceleb1.dev.meta └── voxceleb1.test.meta其中data/vox/csv/train.csv由split_ratio: 0.9控制从 dev 集切分(90% 训练、10% 内部验证),enroll.csv与test.csv供验证阶段构建 enrollment/test 嵌入。label2id.txt是说话人标签到数字 id 的映射,对应训练分类头的类别索引。
八、Stage 1:模型训练
训练由 local/train.sh 驱动,最终调用 train.py。脚本根据CUDA_VISIBLE_DEVICES自动判断设备:多卡时通过paddle.distributed.launch启动分布式训练,单 CPU 时直接单进程运行:
# GPU(4 卡) CUDA_VISIBLE_DEVICES=0,1,2,3 bash ./local/train.sh ./data/ exp/ecapa-tdnn-vox12-big/ conf/ecapa_tdnn.yaml # 仅 CPU CUDA_VISIBLE_DEVICES= bash ./local/train.sh ./data/ exp/ecapa-tdnn-vox12-big/ conf/ecapa_tdnn.yaml从 train.py 源码可以看到训练主流程的关键步骤:
paddle.set_device(args.device)设置设备;paddle.distributed.init_parallel_env()初始化并行环境,随后用seed_everything(config.seed)固定随机种子——这是多进程训练可复现的必要措施;- 特征侧采用
paddlespeech.audio.compliance.librosa.melspectrogram提取 80 维 fbank(对应配置中sr: 16000, n_mels: 80); - 数据读取使用 CSVDataset,训练时还会通过 build_augment_pipeline 加载 Stage 0 生成的 RIR/噪声 CSV 做语音增强;
- 模型封装为
SpeakerIdetification(backbone=EcapaTdnn(...), num_class=7205),训练目标为 AAM-softmax 说话人分类损失。
训练产生的 checkpoint 存放在exp_dir下(如exp/ecapa-tdnn-vox12-big/),日志写入exp/log目录。
九、Stage 2:模型测试与 EER 评测
测试由 local/test.sh 驱动,调用 test.py 计算说话人验证指标:
CUDA_VISIBLE_DEVICES=0 bash ./local/test.sh ./data/ exp/ecapa-tdnn-vox12-big/ conf/ecapa_tdnn.yaml测试流程分四步(对应 test.py 中的函数):
- 嵌入提取:对 enrollment/test 数据集的每个音频提取 192 维说话人嵌入(
model.backbone(feats, lengths)输出(N, emb_size, 1),squeeze(-1)后得到(N, emb_size)); - 全局嵌入归一化:若配置
global_embedding_norm: True,使用 InputNormalization 对全部嵌入做均值方差归一化——源码注释指出该操作可相对降低约 10% 的 EER; - 余弦打分:遍历 trial 文件,对每对"说话人-语音"计算嵌入余弦相似度,并支持 s-norm 分数归一化(使用
cohort_size: 20000的冒名者 cohort 与n_train_snts: 400000条训练句计算归一化统计量); - EER 计算:
compute_eer基于sklearn.metrics.roc_curve求得等错误率(EER,越低越好)。
十、配置文件详解:ecapa_tdnn.yaml
conf/ecapa_tdnn.yaml 是完整的实验配置,按功能划分为六个区块。仓库还提供了一份轻量版 conf/ecapa_tdnn_small.yaml(模型通道数减半、仅用 VoxCeleb1 训练、epochs 提升到 100),适合快速验证。
10.1 数据配置
| 参数 | 默认值 | 说明 |
|---|---|---|
augment | True | 是否使用 RIR/噪声数据做语音增强 |
batch_size | 32 | 训练 batch 大小 |
num_workers | 2 | DataLoader 子进程数 |
num_speakers | 7205 | 训练说话人类别数(Vox1 1211 + Vox2 5994) |
shuffle | True | 是否打乱数据 |
skip_prep | False | 是否跳过数据预处理 |
split_ratio | 0.9 | dev 集按 9:1 切分训练/验证 |
chunk_duration | 3.0 | 每条语音随机截取的时长(秒) |
random_chunk | True | 是否随机截取 chunk |
verification_file | data/vox1/veri_test2.txt | 评测 trial 文件 |
10.2 特征提取配置
| 参数 | 默认值 | 说明 |
|---|---|---|
sr | 16000 | 采样率 |
n_mels | 80 | Mel 滤波器组数量(fbank 维度) |
window_size | 400 | 窗长,25ms × 16000 / 1000 = 400 采样点 |
hop_size | 160 | 帧移,10ms × 16000 / 1000 = 160 采样点 |
配置注释明确说明当前特征仅支持 fbank。
10.3 模型配置
| 参数 | 默认值 | 说明 |
|---|---|---|
model.input_size | 80 | 输入 fbank 维度 |
model.channels | [1024, 1024, 1024, 1024, 3072] | 各 TDNN 块的通道数 |
model.kernel_sizes | [5, 3, 3, 3, 1] | 一维卷积核大小 |
model.dilations | [1, 2, 3, 4, 1] | 各块膨胀率 |
model.attention_channels | 128 | 注意力统计池化中的注意力维度 |
model.lin_neurons | 192 | 最终说话人嵌入维度 |
对应 EcapaTdnn 的构造函数签名。从源码可以确认 ECAPA-TDNN 的完整结构:初始 TDNN 层 → 多个 SE-Res2Net 块 → 多层特征聚合(MFA,将中间层输出 concat 后经 TDNN 块)→ 注意力统计池化(Attentive Statistics Pooling + BatchNorm)→ 1×1 卷积投影到lin_neurons维嵌入。该实现忠实还原了论文 "ECAPA-TDNN: Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification" 中强调的三大设计:通道注意力(SE-Res2Net)、特征传播(多层特征聚合)与特征聚合(注意力统计池化)。
10.4 训练配置
| 参数 | 默认值 | 说明 |
|---|---|---|
seed | 1986 | 随机种子(与 SpeechBrain 官方配置一致) |
epochs | 10 | 训练轮数 |
save_interval | 10 | checkpoint 保存间隔 |
log_interval | 10 | 日志打印间隔 |
learning_rate | 1e-8 | 循环学习率下界 |
max_lr | 1e-3 | 循环学习率上界 |
step_size | 140000 | 循环学习率周期步数 |
训练侧使用 CyclicLRScheduler(循环学习率调度),learning_rate与max_lr构成其上下界,这也是 SpeechBrain 复现该模型时的标准设置。
10.5 损失函数配置
| 参数 | 默认值 | 说明 |
|---|---|---|
margin | 0.2 | AAM-softmax 角度余量 |
scale | 30 | AAM-softmax 缩放因子 |
对应源码 loss.py 中的AdditiveAngularMargin与LogSoftmaxWrapper:在 softmax 分类头上施加角度间隔,显著增强类间可分性,是当前声纹识别的主流训练范式。
10.6 测试与分数归一化配置
| 参数 | 默认值 | 说明 |
|---|---|---|
global_embedding_norm | True | 全局嵌入归一化(相对降 EER 约 10%) |
embedding_mean_norm | True | 嵌入减均值归一化 |
embedding_std_norm | False | 嵌入除标准差归一化 |
score_norm | s-norm | 打分归一化方式 |
cohort_size | 20000 | 归一化 cohort 中冒名者语音数量 |
n_train_snts | 400000 | 计算归一化统计量使用的训练句数 |
十一、使用预训练模型
官方在 released_model.md 中发布声纹模型。以sv0_ecapa_tdnn_voxceleb12_ckpt_0_2_1.tar.gz为例,使用方式如下:
tar -xvf sv0_ecapa_tdnn_voxceleb12_ckpt_0_2_1.tar.gz source path.sh # 若已处理数据并生成 manifest,可直接执行: CUDA_VISIBLE_DEVICES= bash ./local/test.sh ./data sv0_ecapa_tdnn_voxceleb12_ckpt_0_2_1/model/ conf/ecapa_tdnn.yamltest.sh的--load-checkpoint参数会从解压目录加载模型权重完成评测,因此无需重新训练即可在 VoxCeleb1 协议上复现官方结果。
十二、实验结果参考
RESULT.md 记录了官方发布模型的性能:
| 模型 | 参数量 | 嵌入维度 | 测试集 | Cosine EER | Cosine + S-Norm EER |
|---|---|---|---|---|---|
| ECAPA-TDNN | 85M | 192 | VoxCeleb1 test | 0.8188% | 0.7815% |
作为对照,SpeechBrain 官方实现(Vox1+Vox2 联合训练)在相同协议上的 EER 为 0.90%(无 s-norm)与 0.80%(有 s-norm),PaddleSpeech 的实现处于同一水平量级,验证了该复现流程的有效性。
十三、如何从零跑通整个示例
综合上述各节,从零复现的推荐路径是:
# 1. 进入示例目录 cd examples/voxceleb/sv0 # 2. 加载环境 source path.sh # 3. 完整流水线:数据处理 + 训练 + 测试(使用 run.sh 的默认 4 卡 GPU 设置) bash run.sh --stage 0 --stop_stage 2 # 或者手动分步执行: bash ./local/data.sh ./data/ conf/ecapa_tdnn.yaml CUDA_VISIBLE_DEVICES=0,1,2,3 bash ./local/train.sh ./data/ exp/ecapa-tdnn-vox12-big/ conf/ecapa_tdnn.yaml CUDA_VISIBLE_DEVICES=0 bash ./local/test.sh ./data/ exp/ecapa-tdnn-vox12-big/ conf/ecapa_tdnn.yaml几点实用建议:
- 磁盘与时间:VoxCeleb2 原始 m4a 转 wav 耗时数小时且占用大量磁盘,转换仅需一次,转换完成后 m4a 可保留备查(
convert.sh不会删除原文件); - 硬件:完整 Vox1+Vox2 训练(
epochs: 10、85M 参数)建议使用多卡 GPU;仅做验证可改用 ecapa_tdnn_small.yaml(通道数减半、单数据集); - 评测细节:EER 计算依赖
sklearn,打分支持余弦与余弦+s-norm 两种模式,可通过score_norm参数切换。
结语
通过examples/voxceleb/示例,PaddleSpeech 提供了一条从原始 VoxCeleb 音频到生产级声纹系统的完整可复现链路:标准化的 m4a→wav 数据转换、manifest/CSV 索引生成、基于 AAM-softmax 的 ECAPA-TDNN 说话人分类训练、余弦打分与 EER 评测,以及官方预训练模型。无论是入门声纹识别还是在此基础上做工程化改造(如替换骨干网络、切换打分后端),本文梳理的配置参数与源码调用关系都可以作为直接的落地参考。
- 人工智能
- 语音
- 音频
【免费下载链接】PaddleSpeech
Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.
相关推荐
PaddleSpeech 声纹识别实战指南:基于 VoxCeleb 数据集训练与评估 ECAPA-TDNN 说话人验证模型
PaddleSpeech 声纹识别实战指南:基于 VoxCeleb 数据集训练与评估 ECAPA TDNN 说话人验证模型 本指南以 PaddleSpeech
人工智能语音音频PaddleSpeech 声纹识别实战:基于 VoxCeleb 训练与测试 ECAPA-TDNN 说话人验证系统
PaddleSpeech 声纹识别实战:基于 VoxCeleb 训练与测试 ECAPA TDNN 说话人验证系统 本指南以 PaddleSpeech 仓库中 e
人工智能语音音频NLP媒体生成PaddleSpeech 说话人验证实战:基于 VoxCeleb 数据集与 ECAPA-TDNN 的完整训练评测指南
PaddleSpeech 说话人验证实战:基于 VoxCeleb 数据集与 ECAPA TDNN 的完整训练评测指南 导读 本文以 PaddleSpeech 仓
人工智能语音音频NLP媒体生成
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考