pyannote.audio 保姆级部署教程:工业级说话人分离,从录音到谁在什么时候说话全流程
pyannote.audio 是一个开源的说话人分离(Speaker Diarization)工具包,用 Python 写成,基于 PyTorch。它的核心能力是:给它一段多人对话录音,它能告诉你"谁在什么时候说了话"——比如 0.2s–1.5s 是说话人 A,1.8s–3.9s 是说话人 B。这就是行业里常说的"说话人分离"或"语音日志"。当前最新开源版本是 community-1(2026 年 10 月发布),在 AMI、ALIMeeting、VoxConverse 等公开基准上把 DER(说话人分离错误率)压到了 11%–20% 区间,是目前开源 SOTA。本文按官方 README,从安装、HuggingFace token 配置、跑通第一段多人对话分离、到与 Whisper 拼接出"谁+说了什么"的完整字幕。

一、项目介绍与适用场景
pyannote.audio 由 CNRS(法国国家科学研究中心)开发维护,MIT 协议发布。它不是一个"模型",而是一个"流水线工具箱"——内部包含语音活动检测、说话人 embedding、聚类等多个预训练模型,按顺序串成完整的 diarization 流水线。官方提供两条路线:community-1(完全开源、自托管、MIT)和 precision-2(pyannoteAI 商业云服务,需 API Key)。本文以 community-1 为主。
适用场景:
- 会议纪要/访谈整理:多人对话录音自动分离出"谁在说话",再喂给 Whisper 转写,生成带说话人标签的字幕;
- 呼叫中心质检:识别客户与客服的轮次,统计每方说话时长;
- 播客/视频字幕:给多人对话视频加 speaker 标签;
- 研究/标注工具:作为说话人分离 baseline 或数据标注流水线的一环。
与站点此前写过的 WhisperX 相比,pyannote.audio 是 WhisperX 底层调用的 diarization 引擎本身——WhisperX 只是把 pyannote + Whisper 串起来的薄封装。如果你需要自定义聚类参数、微调说话人模型、或直接在 C++/Rust 服务里嵌入 diarization,直接用 pyannote.audio 比用 WhisperX 更底层、更灵活。
什么是"说话人分离"?想象一段会议录音:你知道里面有 3 个人在说话,但不知道谁是谁、什么时候开始说的。说话人分离(Speaker Diarization)就是自动回答这两个问题:"每一段语音是谁说的"。它的输出通常是一个时间轴,比如:
0.0s – 2.3s Speaker_0
2.5s – 5.1s Speaker_1
5.3s – 8.0s Speaker_0
8.2s – 10.4s Speaker_2
这个结果本身不告诉你"说了什么",只告诉你"谁说的"。但把它和 ASR(比如 Whisper)结合,就能得到"谁说了什么"的完整字幕——这就是会议纪要、访谈整理、播客字幕的标准流水线。
community-1 相比上一代 legacy 3.1 有多大提升?官方在 12 个公开基准上做了对比:AMI(IHM)从 18.8% DER 降到 17.0%,ALIMeeting 从 24.5% 降到 20.3%,VoxConverse 从 11.2% 降到 11.2%(持平)。DER 越低越好,17% 意味着每 100 秒音频里只有 17 秒的说话人判断出错。商业云 precision-2 在 community-1 基础上再降 3-8 个百分点,同时速度快 2.2-2.6 倍(H100 上 14s/小时 vs 31s/小时)。
二、核心功能逐条拆解
- 说话人分离(Diarization):输出每个说话人的起止时间区间。对应入口:
pipeline("audio.wav")。 - 社区开源流水线 community-1:完全自托管,MIT 协议,无需付费 API。
- 商业云 precision-2:官方托管服务,DER 更低、速度更快(H100 上 14s/小时 vs community-1 31s/小时)。
- ProgressHook 进度显示:长音频处理时实时显示进度。
- GPU 加速:
pipeline.to(torch.device("cuda"))一行切 GPU。 - 多 GPU 训练:基于 PyTorch Lightning,支持分布式训练。
- 可选遥测:通过
PYANNOTE_METRICS_ENABLED环境变量控制是否发送匿名统计。 - 微调能力:预训练流水线可以用你自己的数据继续微调。
- Rust/C++ 绑定:官方提供 onnxruntime 绑定,可嵌入非 Python 服务。
- 遥测开关:完全可控,可一键关闭所有匿名上报。
三、全套官方链接
| 类型 | 链接 |
|---|---|
| GitHub 仓库 | https://github.com/pyannote/pyannote-audio |
| 官方文档 | https://docs.pyannote.ai |
| 官方 Demo | 无(库,无在线 Demo) |
| HuggingFace 模型 | https://hf.co/pyannote |
| License | MIT |
四、硬件与环境前置要求
官方 README 的 community-1 安装步骤明确:
- 系统:任意 Linux/macOS/Windows(WSL2);
- ffmpeg:必须安装(torchcodec 解码依赖);
- Python:官方推荐用 uv 管理(
uv add pyannote.audio),也支持 pip; - GPU:推荐 NVIDIA GPU(community-1 在 H100 上 31s/小时音频);无 GPU 也能跑,但会慢很多;
- HuggingFace 账号:必须注册,且手动在网页上接受
pyannote/speaker-diarization-community-1的用户协议; - HuggingFace Access Token:在 hf.co/settings/tokens 创建一个 read 权限的 token。
官方出处:README "community-1 open-source speaker diarization" 小节。
补充说明:无 GPU 能不能跑?能,但慢。官方基准数据是在 H100 80GB 上测的(31s/小时音频)。如果你只有 CPU 或 4GB 显存的入门卡,跑 1 小时音频可能要 10-30 分钟。这种情况下建议走 precision-2 云服务(官方托管,按使用量计费),或者用 ffmpeg 先把长音频切成小段慢慢跑。
五、多平台部署步骤
5.1 安装(官方)
第 1 步:装 ffmpeg:
# Ubuntu/Debian
sudo apt install ffmpeg
# macOS
brew install ffmpeg
第 2 步:安装 pyannote.audio(官方推荐 uv,也给 pip 命令):
# 官方推荐:用 uv
uv add pyannote.audio
# 或用 pip
pip install pyannote.audio
第 3 步:在 HuggingFace 网站上: 1. 注册/登录 huggingface.co; 2. 打开 https://hf.co/pyannote/speaker-diarization-community-1,点 "Accept the conditions" 接受用户协议; 3. 打开 https://hf.co/settings/tokens,创建一个 read 权限的 Access Token,复制下来。
5.2 跑通最简 diarization(官方示例原文)
import torch
from pyannote.audio import Pipeline
from pyannote.audio.pipelines.utils.hook import ProgressHook
# Community-1 open-source speaker diarization pipeline
pipeline = Pipeline.from_pretrained(
"pyannote/speaker-diarization-community-1", token="HUGGINGFACE_ACCESS_TOKEN"
)
# send pipeline to GPU (when available)
pipeline.to(torch.device("cuda"))
# apply pretrained pipeline (with optional progress hook)
with ProgressHook() as hook:
output = pipeline("audio.wav", hook=hook) # runs locally
# print the result
for turn, speaker in output.speaker_diarization:
print(f"start={turn.start:.1f}s stop={turn.end:.1f}s speaker_{speaker}")
# start=0.2s stop=1.5s speaker_0
# start=1.8s stop=3.9s speaker_1
# start=4.2s stop=5.7s speaker_0
# ...
逐段解释:Pipeline.from_pretrained() 从 HuggingFace 下载 community-1 流水线(首次调用会下载约几百 MB 模型文件);pipeline.to(torch.device("cuda")) 把模型搬到 GPU;pipeline("audio.wav") 对音频跑完整 diarization;output.speaker_diarization 是一个迭代器,每次返回 (Segment, speaker_label),Segment.start/end 是秒数,speaker 是说话人编号(0、1、2...)。
5.3 商业云 precision-2(官方)
如果你不想自己托管 GPU,可以用 pyannoteAI 的云服务:
- 去 https://dashboard.pyannote.ai 创建 API Key(官方说有免费额度);
- 代码:
from pyannote.audio import Pipeline
pipeline = Pipeline.from_pretrained(
"pyannote/speaker-diarization-precision-2", token="PYANNOTEAI_API_KEY"
)
output = pipeline("audio.wav") # runs on pyannoteAI servers
for turn, speaker in output.speaker_diarization:
print(f"start={turn.start:.1f}s stop={turn.end:.1f}s {speaker}")
六、配置文件全部参数解释
pyannote.audio 无独立配置文件,参数主要在 pipeline() 调用时传入。按官方 README 与文档整理:
| 参数 | 作用 | 可选值 | 默认值 | 配置示例 | 改错后果 |
|---|---|---|---|---|---|
token |
HuggingFace Access Token | 字符串 | 必填 | "hf_..." |
没接受用户协议会报 401 |
num_speakers |
说话人数量 | 整数 | 自动 | num_speakers=3 |
强制指定错误会聚类不准 |
min_speakers |
最少说话人数 | 整数 | 无 | min_speakers=2 |
与 max 冲突报错 |
max_speakers |
最多说话人数 | 整数 | 无 | max_speakers=5 |
同上 |
hook |
进度回调 | ProgressHook 实例 | 无 | with ProgressHook() as hook: pipeline("audio.wav", hook=hook) |
不传则无进度显示 |
(以上参数在官方 README 与文档中定义,此处按官方默认行为如实标注。)
调优经验:num_speakers 是最敏感的参数。如果你知道这段录音正好几个人说话,显式传 num_speakers=3 会比自动检测准很多——自动检测需要猜测人数,在说话人少、对话不频繁的场景容易猜错。如果你不确定人数,用 min_speakers=2, max_speakers=5 给一个范围,让模型在范围内自己找最优。ProgressHook 对长音频(>10 分钟)很有用,能实时看到处理到哪一秒了,不至于以为卡死。
七、启动、后台常驻与开机自启
pyannote.audio 是库,不是服务。把它包成 FastAPI:
# diarize_server.py
from fastapi import FastAPI, UploadFile
from pyannote.audio import Pipeline
import torch, os
app = FastAPI()
pipeline = Pipeline.from_pretrained(
"pyannote/speaker-diarization-community-1",
token=os.environ["HF_TOKEN"]
)
pipeline.to(torch.device("cuda"))
@app.post("/diarize")
async def diarize(file: UploadFile):
output = pipeline(file.filename)
segments = [
{"start": turn.start, "end": turn.end, "speaker": speaker}
for turn, speaker in output.speaker_diarization
]
return {"segments": segments}
启动:
export HF_TOKEN=hf_xxxxx
uvicorn diarize_server:app --host 0.0.0.0 --port 50023
systemd unit:
[Unit]
Description=pyannote Diarization Service
After=network.target
[Service]
User=your_user
WorkingDirectory=/your/path
Environment=HF_TOKEN=hf_xxxxx
ExecStart=/usr/bin/uvicorn diarize_server:app --host 0.0.0.0 --port 50023
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now pyannote-server
修改端口:改 --port 50023。
八、功能实操教程
第 1 步:装好 pip install pyannote.audio 与 ffmpeg,准备一段多人对话录音 meeting.wav(16kHz 单声道 wav 最佳)。如果是 mp3 或 m4a,先用 ffmpeg 转成 wav:ffmpeg -i meeting.mp3 -ar 16000 -ac 1 meeting.wav。
第 2 步:在 HuggingFace 网页接受 pyannote/speaker-diarization-community-1 用户协议,创建 read token。注意:这个接受动作必须在网页上点,API 调用不会替你完成——没点过的话第一次运行会报 401。
第 3 步:跑最简 diarization 脚本,等待模型下载(首次约几百 MB),终端会打印:
start=0.2s stop=1.5s speaker_0
start=1.8s stop=3.9s speaker_1
start=4.2s stop=5.7s speaker_0
...
第 4 步:指定说话人数量。如果你知道这段录音正好 3 个人说话:
output = pipeline("meeting.wav", num_speakers=3)
或给个范围:
output = pipeline("meeting.wav", min_speakers=2, max_speakers=5)
第 5 步:与 Whisper 对接,生成带说话人标签的字幕:
from faster_whisper import WhisperModel
# 先 diarize
diarization = pipeline("meeting.wav")
# 再 Whisper 转写
asr = WhisperModel("small", device="cuda")
segments, _ = asr.transcribe("meeting.wav", language="zh")
# 把每个 Whisper 时间戳对齐到 diarization 的说话人
for seg in segments:
mid = (seg.start + seg.end) / 2
for turn, speaker in diarization.speaker_diarization:
if turn.start <= mid <= turn.end:
print(f"[{seg.start:.1f}-{seg.end:.1f}] {speaker}: {seg.text}")
break
第 6 步:关闭遥测。官方默认开启匿名统计,如果你不想发数据:
export PYANNOTE_METRICS_ENABLED=0
第 7 步:把结果导出成 RTTM 文件(行业标准格式,方便喂给其他工具):
with open("meeting.rttm", "w") as f:
for turn, speaker in output.speaker_diarization:
# RTTM 格式:SPEAKER filename 1 start dur <NA> <NA> speaker <NA>
f.write(
f"SPEAKER meeting.wav 1 {turn.start:.3f} {turn.end - turn.start:.3f} "
f"<NA> <NA> {speaker} <NA>\n"
)
RTTM 是 NIST 定义的 diarization 标注格式,所有主流 ASR/评测工具都支持。导出后可以直接喂给 Whisper、或用 pyannote.metrics 库算 DER。
第 8 步:批量处理一个文件夹里的所有录音:
import os, glob
pipeline = Pipeline.from_pretrained(
"pyannote/speaker-diarization-community-1", token="hf_xxxxx"
)
pipeline.to(torch.device("cuda"))
for wav_file in glob.glob("./recordings/*.wav"):
print(f"Processing {wav_file}...")
output = pipeline(wav_file)
# 保存每个文件的 diarization 结果
base = os.path.splitext(os.path.basename(wav_file))[0]
with open(f"./outputs/{base}.rttm", "w") as f:
for turn, speaker in output.speaker_diarization:
f.write(f"SPEAKER {base}.wav 1 {turn.start:.3f} {turn.end - turn.start:.3f} <NA> <NA> {speaker} <NA>\n")
第 9 步:可视化 diarization 结果。把结果画成时间轴图,方便肉眼检查:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(12, 2))
colors = {0: 'tab:blue', 1: 'tab:orange', 2: 'tab:green'}
for turn, speaker in output.speaker_diarization:
ax.barh(0, turn.end - turn.start, left=turn.start, height=0.5,
color=colors.get(speaker % len(colors), 'gray'), alpha=0.7)
ax.set_xlabel('Time (seconds)')
ax.set_title('Speaker Diarization Result')
plt.tight_layout()
plt.savefig('diarization_timeline.png', dpi=150)
这张图会把每个说话人的时间段画成彩色横条,一眼就能看出对话轮次是否合理。
九、全套报错故障排查
-
报错:
401 Client Error: Unauthorized或You must accept the user conditions。 原因分析:HuggingFace token 没填,或没在网页上接受pyannote/speaker-diarization-community-1用户协议。 分步解决方案:先去 https://hf.co/pyannote/speaker-diarization-community-1 点 "Accept";再确认token=参数填的是 read 权限的 token。 -
报错:
ffmpeg not found。 原因分析:torchcodec 解码音频需要 ffmpeg。 分步解决方案:sudo apt install ffmpeg或brew install ffmpeg。 -
报错:
CUDA out of memory。 原因分析:community-1 流水线需要显存。 分步解决方案:关掉其他占显存的进程;换用更小的 batch;或走 precision-2 云服务(不占本地显存)。 -
报错:模型下载很慢或失败。 原因分析:HuggingFace 访问慢。 分步解决方案:设置
HF_ENDPOINT=https://hf-mirror.com后重试;或手动从镜像站下载模型文件放到~/.cache/huggingface/。 -
报错:说话人数量不对(把两个人当成一个人,或把一个人切成两个)。 原因分析:自动聚类阈值不合适。 分步解决方案:显式传
num_speakers或min_speakers/max_speakers;或改用 precision-2 云服务,官方数据显示它在难样本上 DER 显著更低。 -
报错:音频处理时内存暴涨。 原因分析:几小时长音频一次性加载。 分步解决方案:用 ffmpeg 先把长音频切成小段分别处理,再合并结果;或升级到 precision-2(官方托管,不占本地内存)。
-
报错:
torch.hub.load或模型下载卡在某个进度。 原因分析:HuggingFace 大模型下载慢,国内网络不稳定。 分步解决方案:设置环境变量HF_ENDPOINT=https://hf-mirror.com走国内镜像;或用huggingface-cli download pyannote/speaker-diarization-community-1 --local-dir ./model提前手动下载好,再指定本地路径加载。 -
报错:结果里出现了一个不存在的 speaker(比如背景噪音被识别成 speaker_2)。 原因分析:环境噪音被误判成语音。 分步解决方案:先跑一遍 Silero VAD 做预处理,把纯静音段切掉再喂给 pyannote;或显式传
num_speakers强制限制说话人数量。
十、升级、回滚与卸载
升级:pip install -U pyannote.audio。官方 CHANGELOG 记录了 community-1 与 precision-2 的版本变化,升级前建议看一眼。2026 年 10 月发布的 community-1 是大版本更新,从 legacy 3.1 迁过来需要重新接受模型用户协议、重新下载模型文件。
备份建议:HuggingFace 模型缓存在 ~/.cache/huggingface/,可以单独备份;自己写的 diarization 脚本记得版本管理;如果有微调过的自定义模型,务必单独打包保存。
回滚:pip install pyannote.audio==<旧版本号>。
卸载:pip uninstall pyannote.audio;systemd 方式 sudo systemctl disable --now pyannote-server 并删 unit 文件;删 HF 缓存目录。
十一、商用许可与合规风险提示
代码协议为 MIT,允许商用、修改、分发,只需保留版权声明。需要注意三点:第一,community-1 预训练模型托管在 HuggingFace 上,使用时需接受该模型卡上的用户协议(官方未在 README 中单独列出商用限制,但建议商用前再读一遍模型卡);第二,diarization 输出的"说话人编号"(speaker_0、speaker_1)本身不涉及隐私,但如果你的产品把 diarization 结果与声纹库关联识别出真实身份,会触发声纹识别相关法规,需要自行评估合规风险;第三,telemetry 遥测默认开启,虽然官方承诺不收集可识别身份的信息,但对数据敏感的企业用户建议在部署时通过 PYANNOTE_METRICS_ENABLED=0 显式关闭。本教程不构成法律意见。
参考链接
- GitHub 仓库:https://github.com/pyannote/pyannote-audio
- 官方文档:https://docs.pyannote.ai
- HuggingFace 模型:https://hf.co/pyannote
- community-1 模型卡:https://hf.co/pyannote/speaker-diarization-community-1
- pyannoteAI 云服务:https://dashboard.pyannote.ai
附录:community-1 vs precision-2 怎么选
| 维度 | community-1(开源自托管) | precision-2(商业云) |
|---|---|---|
| 费用 | 免费(自己出 GPU) | 有免费额度,超出按量付费 |
| 数据隐私 | 完全本地,数据不出服务器 | 上传到 pyannoteAI 服务器 |
| DER 准确率 | AMI IHM 17.0% | AMI IHM 12.9% |
| 速度(H100) | 31s/小时音频 | 14s/小时音频 |
| 部署复杂度 | 需 GPU、需装 ffmpeg、需 HF token | 只需 API Key |
| 适合场景 | 数据敏感、批量处理、二次开发 | 快速上线、不想管 GPU、对准确率要求高 |
一句话总结:个人开发者、研究原型、数据合规要求高的项目,用 community-1 自托管;企业生产环境、追求准确率和速度、不想维护 GPU,用 precision-2 云服务。两者可以先用 community-1 跑通流程,后续按需迁移到 precision-2——API 完全兼容,只改 from_pretrained 的模型名即可。