2、唤醒词数据集构建:数据采集要求与样本比例控制

好,咱们直接进入正题。数据集构建这件事,说白了就是给模型喂饭——你喂什么,它就学什么。我见过太多团队在模型结构上花了大把时间,结果数据集一塌糊涂,最后模型效果惨不忍睹。嗯,今天我就把这块的经验掰开揉碎了讲给你听。

2.1 数据采集的硬性要求:采样率、声道、位深

先说说最基础的三个参数。你想想看,如果连原始数据都不规范,后面再怎么折腾也是白搭。

参数 要求值 为什么是这个值?
采样率 16kHz 人声主要能量集中在4kHz以下,16kHz足够覆盖。我试过8kHz,高频信息丢失严重,唤醒词里的摩擦音(比如“西”、“七”)基本听不清了。
声道数 单声道 唤醒词场景通常是单麦克风,双声道反而增加计算量。说白了,没必要。
位深 16bit 16bit的动态范围约96dB,足够覆盖安静环境到嘈杂街道。8bit的话,底噪会很明显。
⚠️ 我曾经踩过的坑: 有一次合作方给了48kHz、24bit的录音,说是“高保真”。结果模型训练时显存直接爆了,而且高频信息对唤醒词识别几乎没有帮助。后来我强制降采样到16kHz、16bit,效果一点没变差,训练速度还快了30%。所以别迷信高规格,合适就好。

2.2 正样本与负样本的比例控制

正样本就是你的唤醒词,比如“小爱同学”、“嘿Siri”。负样本就是其他所有声音——人说话、电视声、关门声、甚至咳嗽声。

比例怎么定?我个人习惯是 1:3 到 1:5。为什么?

  • 正样本太少:模型学不到唤醒词的稳定特征。比如你只录了100条“你好小智”,模型可能只记住了某个人的口音。
  • 负样本太少:模型会变成“惊弓之鸟”,随便一点声音就触发。我见过一个项目,负样本比例只有1:1,结果在办公室环境下误唤醒率高达40%。
  • 负样本太多:模型会过于保守,真正喊唤醒词时反而不响应。说白了,就是“装死”。
💡 我的经验值: 1:4 是个不错的起点。正样本至少5000条,负样本20000条以上。如果条件允许,负样本里最好包含20%左右的“近似词”——比如唤醒词是“小度”,那“小杜”、“小肚”、“小兔”这些发音接近的词都要加进去。

2.3 数据增强技术:让模型更皮实

数据增强,说白了就是“无中生有”。你只有1000条录音,但通过加噪、变速、调音量,可以变出10000条。我刚开始做的时候也觉得这是“作弊”,后来发现——这是必须的。

2.3.1 加噪

模型在安静环境下表现很好,一到嘈杂环境就拉胯?加噪就是解决这个问题的。

# 一个简单的加噪示例(Python伪代码)
import numpy as np
import soundfile as sf

# 读取干净语音和噪声
speech, sr = sf.read('wake_word.wav')
noise, _ = sf.read('cafe_noise.wav')

# 随机截取一段噪声,长度与语音对齐
noise_cut = noise[:len(speech)]

# 按信噪比混合(SNR=10dB)
snr = 10  # 信噪比,越小噪声越大
speech_power = np.mean(speech**2)
noise_power = np.mean(noise_cut**2)
scale = np.sqrt(speech_power / (noise_power * 10**(snr/10)))
mixed = speech + scale * noise_cut

# 保存
sf.write('mixed_10dB.wav', mixed, sr)

我个人习惯准备5-10种不同类型的噪声:咖啡馆、马路、地铁、风扇、电视、甚至雨声。每种噪声按 SNR 0dB、5dB、10dB、15dB 各混一批。这样模型就能适应各种场景。

🔧 小技巧: 加噪时别只加一种。我试过只加白噪声,结果模型在真实场景下表现很差。白噪声太“均匀”了,真实噪声是有节奏的、有突变的。所以尽量用真实环境录音。

2.3.2 变速

不同人说话速度不一样。有人喊“小爱同学”像机关枪,有人像慢动作。变速就是让模型适应这种差异。

  • 速度因子 0.8~1.2:这是安全范围。低于0.8声音会变得很奇怪,高于1.2会像快进。
  • 注意保持音调:简单的变速会改变音调(像“唐老鸭”效果)。建议用 WSOLA 或 PSOLA 算法,保持音调不变只变速度。

我记得有一次,一个用户说话特别慢,模型死活不识别。后来发现是训练数据里全是正常语速,没有慢速样本。加了0.85倍速的增强后,问题就解决了。

2.3.3 音量调整

这个最简单,但也最容易忽略。你想想看,有人对着麦克风喊,有人离得远轻声说,音量差异可能达到30dB以上。

# 音量调整示例
import random

# 随机调整增益,范围 -6dB 到 +6dB
gain_db = random.uniform(-6, 6)
gain_linear = 10 ** (gain_db / 20)
adjusted = speech * gain_linear

# 注意:不要超过0dBFS,否则会削波
if np.max(np.abs(adjusted)) > 0.99:
    adjusted = adjusted / np.max(np.abs(adjusted)) * 0.99

我建议音量调整范围在 -10dB 到 +6dB 之间。太小声模型听不见,太大声会削波失真。嗯,这里要注意:削波后的声音会引入高频谐波,模型可能会学到错误的特征。

2.4 数据增强的组合策略

别一股脑把所有增强都用上。我推荐一个顺序:

  1. 先变速:改变时间长度
  2. 再音量调整:改变响度
  3. 最后加噪:模拟真实环境

为什么这个顺序?因为变速和音量调整会改变噪声的特性。如果先加噪再变速,噪声也会被变速,听起来不自然。我试过反过来,效果差不少。

📊 最终数据集构成建议:
类别 比例 说明
原始正样本 20% 保持原样,作为基准
加噪正样本 40% 各种噪声、各种SNR
变速正样本 20% 0.8x~1.2x
音量调整正样本 20% -10dB~+6dB
负样本 正样本的3~5倍 包含近似词、环境音、其他语音

最后说一句:数据增强不是越多越好。我见过有人把一条数据增强100倍,结果模型过拟合到增强模式上去了。适可而止,5-10倍就够用了。

好,这一章就到这里。下一章咱们聊聊标注工具的选择和标注规范——这块也是个大坑,我当年可没少往里跳。