用 pyannote.audio 3.1 的 speaker-diarization-3.1 跑一段两人辩论的录音,采样率 16k,时长 8 分钟。结果两处明显的抢话段落只标了 SPEAKER_00,另一人的声音被吞掉,DER 算出来 18%。试过把 clustering.threshold 从 0.7 调到 0.5,speaker 数量变多但抢话处仍只有一个。
一开始怀疑是「min_cluster_size 偏大,短促的插话被合并」,查了一圈,方向不对。
原因不止一个,得分开看。重叠语音段落在聚类时被归到能量更高的那个人。少数情况下是没有启用重叠检测,分割阶段就把双人段判成单人。
还有一种情况,VAD 把抢话段当成噪声直接丢掉。
第一件事是看分段结果里有没有重叠区间
python -c "from pyannote.audio import Pipeline;p=Pipeline.from_pretrained('pyannote/speaker-diarization-3.1');print([ (s.start,s.end) for s,_ ,_ in p('debate.wav').itertracks(yield_label=True)][:5])"
显式传入说话人数约束
python -c "from pyannote.audio import Pipeline;p=Pipeline.from_pretrained('pyannote/speaker-diarization-3.1');print(p('debate.wav', num_speakers=2))"
调小聚类阈值后统计 speaker 数量
python -c "print('clustering.threshold=0.5')"
剩下的就是把抢话片段单独切出来复核两路能量
ffmpeg -i debate.wav -ss 00:03:12 -t 6 -ac 1 clip.wav
恢复的判定其实很直接。两处抢话段落都能标出两个 speaker 标签且时间区间有重叠,DER 从 18% 降到 7%,人工回听标签与声音对得上。
提醒一点。说话人分离对重叠语音天生薄弱,给出人数约束比调阈值有效得多,抢话多的场景还要在业务层允许同一时间段挂两个标签。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
