原文:Xiaomi-CocktailASR-1 Technical Report 代码:xiaomi-research/xiaomi-cocktailasr-1(模型权重与推理代码在 HuggingFace: Ease3/Xiaomi-CocktailASR-1)
多说话人场景下的语音识别,长期以来靠的是”分工”:一个模型负责判断这是谁的声音,一个模型负责把这个人的声音从混音里挑出来,再一个模型负责把挑出来的那段转成文字。小米这次放出来的 Xiaomi-CocktailASR-1,最值得说的地方是它把这三件事全塞进了一个模型——不是把三个模块串成一条流水线,而是让参考语音和待识别的混合语音走同一条编码通路,剩下的”认人”和”转录”全交给一个 Qwen3-8B 自己去完成。
这个做法乍一看有点反直觉:模块化分工不是工程上更稳的做法吗?要弄清楚”合并”为什么反而是件难事、以及 CocktailASR-1 具体怎么把它做成的,得先看看过去这几个模块分开长什么样,拼起来又卡在哪。
目标说话人语音识别(Target-Speaker ASR,TS-ASR)要解决的是”鸡尾酒会问题”:一段混着好几个人说话的录音,只把某个人(提供一段参考语音来指定”是谁”)的话转成文字。这个方向此前主要有两条路:
这两条路还共享一个更根本的缺陷:它们都没有一个环节被设计来判断”目标说话人到底在不在这段音频里”。分离模型总会输出点东西,声纹条件信号也总会被注入,下游 ASR 自然也总会给出一段转录——即便参考说话人压根没出现在混音里,模型也只会一本正经地编一段文本出来,而不是老实说”没有这个人”。
这就是这个方向一直绕不开的核心矛盾:为多说话人场景做的优化,会拖累单说话人场景的保真度;而且不管怎么优化,都没有天然的拒识能力。
CocktailASR-1 的解法是把上一节说的两个环节都拿掉——没有独立的声纹验证模型,也没有独立的语音分离模块。参考语音和待识别的混合语音被拼接成一整段波形,一起送进同一个 Data2Vec2(D2V2)音频编码器,编码结果直接喂给 Qwen3-8B。
换句话说,”这段混音里哪一段是目标说话人”这件事,不再是由某个专门模块提前算好再交给 ASR,而是变成了 LLM 在自己的 self-attention 里做的事:参考语音那一段的帧级表征,和混合语音里每个候选说话人对应时间段的帧级表征,全部平等地摆在同一个序列里,模型跨位置去比较相似度、锁定该转录哪一段——这本身就是 Transformer 最擅长干的活。
这个设计正好对上第 2 节的两个痛点:D2V2 编码器处理单说话人语音时,走的是跟普通 ASR 完全一样的路径(后面会看到,Stage 1 训练本质上就是纯 ASR),不存在”额外条件信号扰乱正常识别”的问题;而参考音、目标音、输出文本全部处于同一个自回归序列里,只要训练数据里放了”参考说话人缺席”的负样本,模型自然有地方去学会输出空,不需要额外的拒识逻辑。
如下图,多说话人 SOTA、单说话人不掉分、拒识、CoT 推理这四个能力,在 CocktailASR-1 里是靠这同一套统一编码同时拿到的,不是靠四个子系统分别优化再拼起来:

上面说的”同一套编码”具体怎么落地,结合 HuggingFace 上开源的 modeling_mic_asr.py 和 feature_extraction_mic_asr.py(通过 trust_remote_code 加载)能看得很清楚。
输入怎么拼:MicAsrFeatureExtractor.prepare_audio 先把参考音频和目标音频分别做峰值归一化(峰值统一标准化到 0.99),再处理参考音频的长度——太短就在 1-4 秒范围内随机采样一个目标长度并做零填充,太长就同样随机采样一个 1-4 秒的窗口,从原音频里随机截取一段(不是固定截头或截尾);处理好的参考片段记作 ref_cut。目标音频前面拼上 1 秒静音。最终喂给模型的是一整条 1D 波形:
waveform = ref_cut ⊕ [1秒静音] ⊕ target
怎么编码:这整条波形一起送进 MicAsrAudioEncoder。里面的 D2V2 编码器(embed_dim=1280,0.6B 参数)先把波形转成 FBank 特征(25ms 窗、10ms 步长),再过两层 stride=2 的卷积做时间维下采样(合计 4 倍),大致每 40ms 输出一个帧级表征——也就是说一段 6 秒的拼接音频,大概会变成 150 个左右的帧级 token。这些表征经过一层 in_proj(Linear(1280, 1280))和一层 out_proj(Linear(1280, 4096))两级线性映射,4096 正好是 Qwen3-8B 的隐藏维度——这一步就是论文里说的 Adapter,做的事情很直接:把音频编码器的输出维度对齐到 LLM 能吃的维度。
怎么”贴”进 LLM:拿到形状为 [1, seq_len, 4096] 的音频向量后,代码构造了一个输入 token 序列:
input_ids = [audio_token_index] * seq_len + prompt_ids
audio_token_index(词表里预留的一个占位 id,值是 151669)先占住音频对应的每一个位置,后面接文本 prompt 编码出的 token id。真正的音频向量是通过在 Qwen3 的 embed_tokens 模块上挂一个 forward hook 塞进去的:hook 在词嵌入查表完成之后,把 input_ids 里等于 audio_token_index 的那些位置,用 masked_scatter 直接替换成前面算出来的音频向量——这样就把连续的音频表征”贴”进了离散 token 序列里,不需要改动 Qwen3 本身的 embedding 层。替换后的整条序列送进 Qwen3 做标准的自回归 generate(),从 input_ids 长度之后的部分开始解码成文本。

不同任务下输入输出分别是什么:整个流程只有 prompt 文本和生成长度上限不同,前向计算逻辑完全一样。
| 场景 | 输入(音频) | 输入(prompt) | 输出 |
|---|---|---|---|
| 标准 TS-ASR | ref_cut ⊕ 静音 ⊕ target | prompt_standard:仅要求转录目标说话人 | 目标说话人的转录文本 |
| CoT 模式 | 同上 | prompt_cot:额外要求逐步推理,<think>/<answer> 标签输出,max_new_tokens 从 256 提到 512 | <think> 内是推理过程,<answer> 内是最终转录 |
| 负样本拒识 | ref_cut(说话人不在 target 里)⊕ 静音 ⊕ target | 与标准模式相同 | 空字符串 |
值得强调的是最后一行:代码里没有任何显式的相似度阈值判断逻辑去触发”拒识”,走的和标准模式完全一样的代码路径。模型只是在训练阶段学会了在”参考说话人缺席”这种输入模式下,直接把生成结果收敛成空——这也解释了为什么第 2 节说的那种拒识能力,在其他方案里天然缺失:不是加个阈值就能补上的,得是训练目标里就有这一项。
如果一上来就把多说话人抗干扰、单说话人保真度、拒识这三件互相拉扯的能力一次性塞进训练目标,模型很容易找不到平衡点——这正是第 2 节说的核心矛盾在训练侧的体现。CocktailASR-1 用了一个四阶段的课程学习(curriculum)来分解这个问题:

这个顺序等于是把”听清楚 → 认人 → 说理由 → 精调”拆成四步走,每一步都在前一步已经稳定的能力上叠加新目标,而不是让模型同时应付所有冲突。
CoT 数据长什么样,看下图三个例子(单说话人、双说话人混合、负样本):

结构是固定的:先给出音频里参考语音段、静音段、待识别语音段各自的时间戳;再判断参考说话人的性别;再对混合音频里出现的每个候选说话人,给出性别和与参考语音的相似度打分(就是上一节说的那个 1-5 等级);最后比较各候选人的打分,选出最高分对应的说话人,若最高分低于 3 则判定为目标缺席。
先说数字:CoT 带来的 WER 提升并不大,LibriMix 2mix 上从 4.11% 降到 3.87%,3mix 上几乎没有变化(12.287% → 12.285%)。
| Test Set | Standard mode | CoT mode |
|---|---|---|
| LibriMix 2mix | 4.11 | 3.87 |
| LibriMix 3mix | 12.287 | 12.285 |
| LibriSpeechMix 2mix | 2.90 | 2.88 |
| LibriSpeechMix 3mix | 4.91 | 4.81 |
如果只看这张表,CoT 这个设计的性价比似乎不高——但报告里给出的定位本来就不是”靠推理链条把识别准确率再往上拱一拱”,而是两件事:一是这套结构化推理过程会引导模型显式地去关注声纹这类关键特征,在复杂场景下减少一部分识别错误;二是推理过程本身产出的中间结果——说话人数量、每个人的性别、各自的活跃时间段——对需要更深层语音理解的下游任务(比如会议摘要、说话人日志)是可以直接复用的辅助信息,不用再单独跑一个 diarization 模型去算这些东西。换句话说,CoT 的价值更多体现在把”为什么选中这个人”的中间过程变成一份可读、可复用的结构化输出,而不是单纯换取更低的 WER。
先看多说话人合成数据集(LibriMix / LibriSpeechMix 的 2mix、3mix):
| Model | LibriMix 2mix | LibriMix 3mix | LibriSpeechMix 2mix | LibriSpeechMix 3mix |
|---|---|---|---|---|
| Xiaomi-CocktailASR-1 | 4.11 | 12.29 | 2.90 | 4.91 |
| Qwen3-ASR-1.7b | 68.75 | 106.04 | 92.17 | 160.82 |
| StepAudio2 | 71.23 | 121.08 | 92.72 | 164.66 |
| Gemini-2.5-pro | 48.41 | 76.10 | 30.69 | 52.34 |
| TCP | 4.84 | 12.23 | - | - |
| CONF-TSASR | - | - | 5.40 | 7.60 |
| MT-LLM | 6.70 | 16.2 | - | - |
| TS-VAD(460h) | 6.61 | 14.81 | 7.92 | 15.97 |
| Whisper-SS-TTI | 7.97 | 21.97 | - | - |
| Transformer-SA-ASR | - | - | 6.40 | 8.50 |
Qwen3-ASR、StepAudio2 这些主流语音大模型在这类强重叠的合成多人数据上直接崩到 60%-160% 的 WER 区间——说明它们本质上没有针对多说话人场景做过专门优化,只是”能处理干净语音”。CocktailASR-1 在 LibriMix 2mix 上做到 4.11%,相对此前 SOTA(TCP,4.84%)提升 15.1%。
真实会议录音(AMI-SDM、AliMeeting-Far)上的结果同样领先:
| Model | AMI SDM | AliMeeting Far |
|---|---|---|
| Xiaomi-CocktailASR-1 | 21.81 | 20.63 |
| Qwen3-ASR-1.7b | 38.18 | 39.64 |
| StepAudio2 | 110.50 | 76.82 |
| Whisper Large-v2 | 36.40 | - |
| Gemini-2.5-pro | 52.95 | 56.75 |
| SQ-Whisper | 22.0 | - |
| MC-TS-ASR | - | 27.50 |
再看单说话人场景——这部分最能体现第 2、3 节说的那个设计取舍:
| Model | LibriSpeech FRR | LibriSpeech Non-empty WER | AliMeeting-near FRR | AliMeeting-near Non-empty WER | AMI-ihm FRR | AMI-ihm Non-empty WER | WenetSpeech(meeting) FRR | WenetSpeech(meeting) Non-empty WER | CommonVoice(zh) FRR | CommonVoice(zh) Non-empty WER |
|---|---|---|---|---|---|---|---|---|---|---|
| Xiaomi-CocktailASR-1 | 0.36 | 1.73 | 0.38 | 6.57 | 0.01 | 8.89 | 0 | 5.81 | 0.73 | 4.95 |
| Qwen3-ASR-1.7b | 0 | 1.87 | 0 | 6.39 | 0 | 10.56 | 0 | 5.84 | 0 | 5.39 |
| StepAudio2 | 0 | 1.58 | 0 | 6.82 | 0 | 37.54 | 0 | 5.46 | 0 | 5.07 |
| Whisper Large-v2 | 0 | 2.70 | - | - | 0 | 16.90 | - | - | 0 | 26.8 |
| Gemini-2.5-pro | 21.31 | 6.77 | 14.95 | 16.10 | 24.30 | 21.02 | 0 | 27.58 | 0.003 | 14.01 |
CocktailASR-1 在单说话人场景下的 WER 和专门做单人 ASR 的 Qwen3-ASR、StepAudio2 基本处于同一水平线(LibriSpeech 上 1.73% vs 1.87%/1.58%),在 AMI-ihm 这种远场场景上还大幅领先(8.89% vs StepAudio2 的 37.54%),同时误拒率(FRR)控制得很低——说明”给模型加拒识能力”这件事没有拖累它在正常场景下的表现,正好对应第 3 节说的”D2V2 处理单说话人语音时不会被额外信号打扰”。
负样本拒识率对比:
| Model | LibriSpeech Neg | Aishell Neg | Chinese in-house Neg |
|---|---|---|---|
| Xiaomi-CocktailASR-1 | 79.59 | 75.35 | 68.54 |
| Qwen3-ASR-1.7b | 0 | 0 | 0 |
| Gemini-2.5-pro | 81.79 | 64.20 | 54.7 |
| StepAudio2 | 0 | 0 | 0 |
没有专门设计过拒识机制的模型,拒识率清一色 0%——Qwen3-ASR 和 StepAudio2 遇到参考说话人缺席的情况,会一本正经地把不存在的人说的话”编”出来;Gemini 有一定拒识倾向但代价是误拒率高(LibriSpeech 上 21.31%),经常把明明存在的目标说话人误判为不存在。CocktailASR-1 在 LibriSpeech 上把误拒率压到 0.36% 的同时,拒识率做到 79.59%。
CocktailASR-1 的核心思路,与其说是架构上的创新,不如说是一次”做减法”:拿掉独立的声纹验证模块和语音分离模块,让参考语音和目标语音走同一条 D2V2→Adapter→LLM 编码通路,把”认出是谁”这件事交给 LLM 自己的 attention 去做。这个减法直接化解了传统级联/条件注入方案里”多人优化拖累单人保真度”和”没有天然拒识能力”这两个老问题;再配合四阶段课程学习把”听清楚、认人、说理由、精调”拆开训,以及规模不小的多人/单人/负样本数据,把这套统一架构真正训成了在多个维度都能打的模型。CoT 这个设计单独看对 WER 的贡献有限,但它把”为什么选中这个人”的判断过程变成了结构化、可复用的中间结果,这个价值不完全体现在评测表的数字里。
权重和推理代码都在 Ease3/Xiaomi-CocktailASR-1 上,trust_remote_code=True 直接能跑,tools/test_batch_scp.py 也给了现成的批量测试脚手架,想在自己的多说话人数据上做个 baseline 对比,成本不算高。
如果这篇文章涉及的语音多模态架构设计、SSL 编码器与 LLM 的 adapter 对齐方式想系统深入,可以看看之前出版的《动手学 AutoML:从 NAS 到大语言模型优化实战》,书里 LLM 效率优化和参数高效微调那部分内容,和本文讲的 encoder-adapter-LLM 三段式架构、以及用 forward hook 做模态拼接的思路有一定的呼应。