2. 唤醒词技术基础

做唤醒词模型,圈里人都知道一句话:数据决定上限,模型只是逼近这个上限。我做了这么多年嵌入式端的语音模型,见过太多团队在模型结构上死磕,结果数据一塌糊涂,最后上线效果惨不忍睹。说白了,数据才是真正的护城河。

这一章,我就把数据采集与标注的全流程掰开揉碎讲清楚。从数据来源到清洗,从标注规范到增强策略,每一步都有我踩过的坑和总结的经验。

核心观点:唤醒词模型的数据质量,直接决定了它在真实场景下的唤醒率和误唤醒率。数据环节省下的功夫,最终都会在线上加倍还回来。

数据采集与标注全流程 数据采集与标注全流程 数据来源 开源数据集 + 自采数据 标注规范 精准标注 + 质量审核 数据清洗 数据增强 加噪 | 变速 | 混响 | 音量扰动 最终训练集 避坑提醒 • 正负样本比例 1:3~1:5 • 标注边界误差 < 20ms • 增强后需人工抽检 关键指标 • 总时长 > 500小时 • 信噪比范围 0~30dB • 语速 0.7x~1.3x

数据来源:开源数据集与自采数据

数据从哪来?无非两条路:开源数据集和自采数据。我个人的习惯是,开源数据集打底,自采数据做定制化补充。两条腿走路才稳当。

开源数据集

目前业界常用的开源语音数据集,我整理了一张表,方便你快速对比:

数据集名称 语言 时长 采样率 特点
Common Voice 多语言(含中文) ~10,000h 48kHz 众包采集,噪声多样
LibriSpeech 英文 ~1,000h 16kHz 有声书朗读,干净语音
aishell-1/2 中文 ~500h 16kHz 普通话,标注精准
MobvoiHotwords 中文 ~100h 16kHz 唤醒词专用,含远场

我的经验:Common Voice 虽然量大,但质量参差不齐。我一般用它做负样本(非唤醒词语音),正样本还是用自采数据或者 aishell 这种标注更准的数据集。

自采数据

自采数据才是真正拉开差距的地方。为什么?因为你的唤醒词最终要在特定设备、特定场景下工作。开源数据再大,也覆盖不了你的麦克风阵列、你的芯片噪声、你的用户口音。

我建议自采数据时注意这几点:

  • 设备一致性:用目标硬件采集,麦克风型号、摆放位置、采样率必须和量产一致
  • 场景覆盖:安静环境、办公室、马路、厨房、车内……至少覆盖 5 种典型场景
  • 说话人多样性:男女老少、不同方言口音,至少 50 人以上
  • 远场近场:0.5m、1m、2m、3m 各采集一批

我记得有一次做智能音箱的唤醒词,开源数据上测试唤醒率 98%,结果到用户家里直接掉到 85%。后来排查发现,用户习惯把音箱放在墙角,远场混响严重。我们补采了一批墙角场景的数据,唤醒率才拉回来。嗯,这就是自采数据的价值。

数据清洗:别让垃圾数据毁了你的模型

数据采集回来,第一件事不是训练,是清洗。我见过太多人拿到数据直接开训,结果模型学了一堆噪声和错误标注。数据清洗说白了就是去伪存真。

我常用的清洗流程:

  1. 静音检测:去除前后静音过长的片段(超过 1 秒静音直接切掉)
  2. 截幅检测:检查波形是否削顶,削顶超过 5% 的片段直接丢弃
  3. 信噪比筛选:信噪比低于 0dB 的片段,基本听不清人声,不要
  4. 时长过滤:唤醒词发音一般在 0.5~2 秒,超出这个范围的可能是误触发
  5. 人工抽检:随机抽 10% 的样本,听一遍,确认标注和内容一致

警告:千万不要跳过人工抽检这一步。我曾经有一个项目,自动清洗后直接训练,结果模型在线上频繁误唤醒。查了两天才发现,清洗脚本有个 bug,把一部分负样本误标成了正样本。从那以后,我每条数据线都强制加一道人工抽检。

标注规范:精准到毫秒级

唤醒词标注和普通语音识别标注不一样。普通 ASR 标注只需要文本转写,但唤醒词标注需要精确的时间边界。为什么?因为模型需要知道唤醒词从哪开始、到哪结束,才能做对齐和判断。

我推荐的标注规范:

标注字段 说明 精度要求
唤醒词文本 如"小爱同学" 字符级准确
起始时间 唤醒词第一个音素的起点 ±10ms
结束时间 唤醒词最后一个音素的终点 ±10ms
说话人ID 区分不同说话人 必填
场景标签 安静/噪声/混响等 可选但推荐

标注工具方面,我个人推荐 Praat 和 Audacity。Praat 可以精确到毫秒级标注,Audacity 适合快速听音和粗标。如果数据量大,可以考虑用 Label Studio 搭建标注平台,支持多人协作。

小技巧:标注时先让标注员听一遍完整音频,再切到波形图标注边界。只看波形容易漏掉弱读音节,只听音频又容易忽略边界精度。两者结合最靠谱。

数据增强:用有限数据模拟无限场景

数据增强是唤醒词模型性能优化的核心手段之一。说白了,就是用算法把有限的数据变出更多花样,让模型见过更多场景,提升泛化能力。

我常用的数据增强方法有四种:

1. 加噪

在干净语音上叠加背景噪声。噪声来源可以是开源噪声库(如 MUSAN、NOISEX-92),也可以自己录。关键是要控制信噪比(SNR)。

# 加噪示例(Python 伪代码)
import numpy as np

def add_noise(clean_audio, noise_audio, snr_db):
    # 计算干净语音和噪声的能量
    clean_power = np.mean(clean_audio ** 2)
    noise_power = np.mean(noise_audio ** 2)
    # 根据 SNR 调整噪声幅度
    scale = np.sqrt(clean_power / (noise_power * 10 ** (snr_db / 10)))
    noisy_audio = clean_audio + scale * noise_audio
    return noisy_audio

# 我一般用 SNR 范围 0~30dB,步长 5dB
# 0dB 是极限情况,30dB 接近干净语音

2. 变速

改变语音的播放速度,模拟不同语速的说话人。注意变速后要保持音高不变(用 WSOLA 算法)。

  • 语速范围:0.7x ~ 1.3x
  • 步长:0.1x
  • 工具:librosa.effects.time_stretch 或 sox

3. 混响

模拟房间反射声,让模型适应远场和封闭空间。混响时间(RT60)是关键参数。

场景 RT60 范围 说明
小房间(卧室) 0.2~0.4s 吸音材料多
大房间(客厅) 0.4~0.8s 家具反射
空旷空间(走廊) 0.8~1.5s 硬反射面多

混响可以用 pyroomacoustics 库生成,或者用卷积混响(IR 文件)。我个人更推荐 IR 文件,因为真实采集的脉冲响应比模拟的更贴近实际。

4. 音量扰动

随机改变音量大小,模拟用户离麦克风远近不同。一般增益范围 -6dB ~ +6dB。

增强策略组合建议:不要一股脑把所有增强都用上。我一般按这个顺序组合:先加噪(SNR 随机),再变速(随机 0.8x~1.2x),最后加混响(随机 RT60)。每条数据随机选 1~2 种增强,避免模型过拟合到增强模式上。

数据质量验证:增强后的最后一道关

数据增强做完,别急着喂给模型。我建议做两件事:

  1. 人工听测:从增强后的数据里随机抽 100 条,听一遍。如果超过 5 条听起来不自然(比如变速后像机器人、噪声过大盖过人声),说明增强参数需要调整。
  2. AB 测试:用原始数据训一个 baseline,用增强数据训一个实验模型,对比唤醒率和误唤醒率。如果增强后唤醒率提升不到 2%,说明增强力度不够;如果误唤醒率飙升,说明增强过度引入了噪声模式。

我记得有一次做车载唤醒词,增强后误唤醒率从 0.5% 飙到 3%。查了半天发现是加噪时用了太多发动机噪声,模型把发动机轰鸣当成了唤醒词的特征。后来把发动机噪声的 SNR 调高到 20dB 以上,问题才解决。你看,数据增强也不是越多越好,得讲究策略。