Xiaomi-CocktailASR-1 跑多人录音 / 说话人标签为什么总跳?

文章导读
同一段多人录音里,说话人标签反复切换,先不要把它直接归到「模型认不准」上。这类跳变通常来自三条线:输入音频的采样率、声道和静音切分边界;推理过程本身是否可复现(随机种子、运行参数);以及调用脚本里的合并与切分后处理把标签改了一遍。把这三条线分开验证,比反复调模型参数更能定位问题。
📋 目录
  1. Ⅰ 用音频工具读出采样率、声道数和静音段分布
  2. Ⅱ 跑同一段音频两次并比较 speaker 标签序列
  3. Ⅲ 截取重叠说话片段单独重跑
  4. Ⅳ 检查调用脚本或配置里的合并与切分参数
  5. Ⅴ 建立音频条件与标签结果记录表
A A

同一段多人录音里,说话人标签反复切换,先不要把它直接归到「模型认不准」上。这类跳变通常来自三条线:输入音频的采样率、声道和静音切分边界;推理过程本身是否可复现(随机种子、运行参数);以及调用脚本里的合并与切分后处理把标签改了一遍。把这三条线分开验证,比反复调模型参数更能定位问题。

先别把标签跳变归因于模型能力。通常的做法是:用 ffprobe 读出采样率、声道和静音区间,固定参数跑同一段音频两次做 diff,再把重叠说话片段单独截出来重跑,最后核对调用脚本里的最小片段长度与合并间隔。能稳定复现的跳变,多半能在音频条件或后处理规则上找到对应项;不能复现的,先固定随机种子和运行参数再比较。这套动作只用于定位问题,不承诺消除标签跳变。

用音频工具读出采样率、声道数和静音段分布

先确认喂进模型的到底是什么音频。采样率和声道数与模型侧期望不一致时,中间往往有一层重采样或声道混音,混音会把不同说话人的能量揉到一起,说话人区分度下降,标签就更容易在相邻片段之间来回换。建议先看流信息,再看静音切分点是不是正好落在说话人交替的位置上。

ffprobe -v error -show_entries stream=index,codec_type,sample_rate,channels,channel_layout,duration -of default=noprint_wrappers=1 input.wav

ffprobe -v error -af silencedetect=noise=-35dB:d=0.4 -f null - input.wav

第一条记录采样率、声道数、声道布局和时长;第二条会把 silence_start 与 silence_end 打到 stderr,据此可以得到明显的静音区间。需要留意三点:一是采样率是否和模型输入要求一致;二是多声道录音是否被当成立体声直接处理,还是被平均成单声道;三是静音段是否密集且很短,短静音往往意味着切分点很多。把这三项写在排查记录里,后面改动才有对照基线。阈值 -35dB 和时长 0.4 秒只是起点,需要结合具体录音的环境噪声调整,安静棚录和会议室录音的合适值不会一样。

跑同一段音频两次并比较 speaker 标签序列

这一步的目的是区分「运行不稳定」和「规则造成的跳变」。前提是同一段音频、同一套参数,只改输出文件名。如果配置里提供随机种子(常见命名是 seed,部分实现还有 temperature、do_sample 之类开关),先固定到同一个值再跑;如果配置里没有可固定的随机项,也照样跑两次,看输出是否一致。

python run_asr.py `--audio` clip.wav `--seed` 0 `--out` run_a.json
python run_asr.py `--audio` clip.wav `--seed` 0 `--out` run_b.json

jq -r '.[] | [.start, .end, .speaker] | @tsv' run_a.json > a.txt
jq -r '.[] | [.start, .end, .speaker] | @tsv' run_b.json > b.txt
diff -u a.txt b.txt

字段名以实际输出结构为准,这里只是形态示意,例如每行是起始时间、结束时间和 speaker 标识:

00:00:01.200  00:00:03.400  SPK_00
00:00:03.400  00:00:04.100  SPK_01

两次输出完全一致时,说明标签序列在给定参数下是可复现的,跳变更可能来自音频条件或后处理规则,而不是运行抖动;两次不一致时,先固定种子、关闭采样类开关,再重复这个对照,直到拿到可复现的基线。建议把 a.txt、b.txt 一起留存,不要只保留最终结果。

截取重叠说话片段单独重跑

多人录音里真正难处理的是同时说话的区间。可以先用音频编辑工具(Audacity、ffmpeg 裁切都行)把重叠区截出来,前后各留半秒左右上下文,做成一个短片段,用和整段相同的参数单独重跑,记录输出的 speaker 数量和切换次数。

Xiaomi-CocktailASR-1 跑多人录音 / 说话人标签为什么总跳?

结果分两种:短片段单独跑时标签正常,放回整段就跳,通常指向切分或合并规则,也可能和长音频的上下文拼接方式有关;短片段单独跑也跳,说明重叠语音本身让说话人归属不稳定,属于音频条件问题,靠加大最小片段长度这类后处理参数只能改变表现形态,不会让重叠区变得可分离。切片段时建议保留原始采样率和声道,不要顺手转成 mp3 或单声道,否则对照条件就变了。

检查调用脚本或配置里的合并与切分参数

后处理是最容易被忽略的一层,因为它发生在模型输出之后。以实际仓库为准,在调用脚本和配置文件里找这几类参数:最小片段长度(常见命名 min_segment、min_speech_duration 之类)、相邻片段的合并间隔(merge_gap、max_gap)、以及按时间窗投票或按最近说话人回填短片的逻辑。这些规则会主动改写标签序列,包括把短片段并入相邻说话人、把同标签的相邻片段合并、对边界片段做平滑。

排查时一次只调一个参数,其余保持不变,跑完记录标签序列变化。更重要的是留一份「后处理前」的原始输出:同一段音频,关闭合并与回填逻辑跑一遍,再开启跑一遍,两份结果直接对比,就能判断标签跳变是模型给出的,还是脚本合并出来的。改这些参数属于后处理层面的调整,不会改变模型对重叠语音的判别能力。

建立音频条件与标签结果记录表

排查过程中最容易丢的是「这次跳变对应哪次配置」。建议用一张固定字段的表,每改一次参数追加一行,字段包含:文件名、采样率、声道数、时长、明显静音区间、是否含重叠说话、随机种子、最小片段长度、合并间隔、输出标签序列摘要、是否可复现、备注。用 CSV 或 Markdown 表格都可以,关键是字段固定、每行可回溯。

文件名采样率/声道重叠种子最小片段合并间隔标签序列可复现
meeting_a.wav16000 / 1有00.5s0.3sSPK_00,SPK_01,SPK_00是
meeting_a.wav16000 / 1有01.0s0.3sSPK_00,SPK_01是

有了这张表,同一段录音在不同参数下的标签差异一眼可见,也能避免把后处理改出来的结果误当成模型波动。表里的时间阈值和参数值都应按你的仓库实际情况填写,不要照搬示例数字。