跳至正文
YC's Blog
返回

深度学习音频笔记 5:关键词检测与持续监听

今天来讲解 KWS,对应 Deep Learning for Audio — Lecture 4。前几篇讨论的是怎样把声音变成文字;这一篇换一个问题:设备怎样从持续到来的声音中,发现值得开始交互的那一句话?

下面沿着任务与评估、模型结构、级联系统、实际部署四条线展开。DTW 和 HMM 部分是衔接前面 ASR 笔记的背景;后面的模型与系统例子按课件展开,公式中的简化例子用于解释机制。

Read this article in English。

KWS 要判断什么?

Keyword Spotting(KWS,关键词检测):如何让设备持续监听,并准确、省电地发现“Hey Siri”这样的唤醒词。主要约束是准确率、延迟、内存和功耗。在讲义给出的端云协同方案中,设备先检测唤醒词,通过后将唤醒词和后续问题发送到服务器,服务器进行验证和 ASR。承担持续监听的端侧模型强调轻量和稳健,后面的精确检查则可以使用更多计算。具体产品也可以把更多处理留在设备上。

应用输入与输出例子
设备唤醒持续音频 → 是否包含唤醒词听到“Hey Siri”后启动交互
录音检索长录音 → 关键词出现位置找出客服录音中“退款”的时间点
短词分类短录音 → 词语类别将一秒录音分类为 “stop”

Wake Word、Hotword、Trigger Word 常用于描述唤醒词。典型语音助手流程是端侧 KWS 发现候选 → 精确检查 → ASR 识别后续请求 → 执行请求。当我们问“Hey Siri,明天天气如何?”时,KWS 负责发现唤醒词,ASR 负责识别后续问题。

怎么评估 KWS?

在讲解模型结构之前,我们先讨论一下应该怎么评估 KWS(课件 pp. 6–7)。

FAR = FP / (FP + TN)
FRR = FN / (FN + TP)

100 次真实唤醒漏掉 5 次,FRR 为 5%;100 小时背景音误触发 2 次 KWS,FA/hour 为 0.02。KWS 文献经常使用固定 FA/h 下的 FRR,例如 FRR @ 0.5 FA/h;这直接表达了误唤醒与漏检之间的取舍。

这里要区分两种分母:FAR 是在定义好的负样本集合上计算的比例,FA/hour 是连续音频上的事件率。一个长录音切成多少个窗口,会改变负窗口的数量;多个相邻高分窗口也可能只对应一次误唤醒。因此,连续检测要先明确怎样合并触发事件,再统计 FA/hour,不能把逐窗口 accuracy 直接当成实际唤醒体验。

通常,降低触发阈值会减少漏检,却增加误唤醒;提高阈值则相反。比较模型时应看整条取舍曲线,或在相同 FA/hour 下比较 FRR,也要记录触发延迟。若检测器使用未来帧或等待多帧确认,这部分等待同样属于延迟。

一个比较经典的数据集是 Speech Commands:

版本规模内容
v1约 65,000 条30 个短词,约一秒录音
v2105,829 条35 个短词

常见词包括 “yes”“no”“stop”“go”。常见 12 类设置由 10 个目标词、unknown 和 silence 组成:unknown 是目标词之外的语音,silence 是静音或背景音类别,两者承担不同的拒识作用。

短词分类和连续唤醒检测相关,但评估问题不同。 一秒录音的分类实验通常已经给好了边界;真实设备还要处理长时间背景、词语边界、重复触发和接在唤醒词后面的请求。讲义 p. 22 的模型汇总适合看结构与规模的变化,不能脱离类别设置、数据划分和评估协议,把不同工作的 accuracy 当成严格排名。

从模板、HMM 到轻量神经网络

模板与 HMM:先处理时间变化

一种早期 KWS 思路是模板匹配,比如先录下一次“小爱同学”,保存它的声学特征。新音频进来后,与模板比较,足够近似的就能触发。但是问题在于,同一个人两次说同样的话也不完全相同,这给模板匹配带来很大的问题。比如说人的语速会变,模板中的“小爱”持续 300 ms,而用户的“小爱”持续 500 ms。DTW(动态时间规整)允许时间轴局部拉伸,找到两段声音之间的最佳对应关系,这一块我们之前讨论 ASR 的文章也讲过。它主要解决的是语速不一致带来的匹配问题,适合录音注册、自定义口令,但单个模板很难覆盖不同人的音色、口音和噪声条件。

之前 ASR 提到的 HMM 将关键词拆成按顺序出现的状态,可以对应音素,也可以是音素内部的子状态。每个状态允许持续若干帧,因此自然能处理语速变化。传统 GMM-HMM 中,GMM 负责评价当前声学特征像哪个状态,HMM 负责约束状态顺序。连续语音中的关键进步,是加入 filler/background model,描述关键词之外的声音。系统在背景和关键词组成的路径中搜索,判断某一段是否足够支持关键词路径,而其他部分由背景模型解释。

DNN:局部判别与后处理

早期 DNN 路线,可以理解成:

相邻若干帧音频特征 → 全连接网络 → 每帧的标签概率 → 平滑与触发逻辑

例如检测“Hey Siri”,单个瞬间通常不够判断,需要把当前帧和附近帧一起送进网络。不同时间位置得到的概率可能抖动,因此再对概率做时间平滑。神经网络负责局部判别,人工设计的后处理负责把局部证据拼起来。它和早期 ASR 的分工很像:声学模型给出逐帧判断,再由其他模块处理时间结构。

讲义的例子使用过去 30 帧和未来 10 帧作为上下文。未来帧需要等待,所以即使网络计算很快,也不是零等待的检测器。对标签 i,一种后验平滑方式是对最近 w 帧求平均:

p_bar[i,j] = (∑_{k=h}^j p[i,k]) / (j − h + 1)
h = max(1, j − w + 1)

这里的 p[i,k] 是第 k 帧上标签 i 的后验概率;平滑后仍需结合触发阈值和时间逻辑做事件判断。

局限也很明确:

SVDF:把时间与特征权重分解

SVDF 是对 DNN 的一种结构化压缩思路(p. 10)。设一个输入窗口有 T 帧、每帧 F 个特征。忽略偏置,一个隐藏单元原本计算:

a = σ(∑_t ∑_f W[t,f] x[t,f])
t = 1, …, T; f = 1, …, F

它要学习整个 T × F 权重矩阵。SVDF 用低秩形式近似,rank-1 的例子是:

W[t,f] ≈ α[t] β[f]

于是可以拆成:

  1. 每一帧先做特征投影:z[t] = ∑_f β[f] x[t,f]。
  2. 再沿时间加权:a = σ(∑_t α[t] z[t])。

以 rank-1 为例,单个滤波器的权重从 TF 变为 T + F。更高秩时可以用多个这样的分量求和,表达能力和成本也随之变化。

思想变化:不再为每种“时间位置 × 特征位置”独立学习权重,而是假设它们可以分解。

这也适合流式执行:历史的 z[t] 可以缓存,新音频到来时只算新增部分。它的名称与 singular value decomposition(奇异值分解)的低秩思想有关;讲义写作 “Single Value Decomposition Filter”,这里保留常用缩写 SVDF。

和 ASR 对应,它接近 TDNN、时间卷积中的有限历史建模:用有界时间上下文提取序列模式。它缓存有限历史,但不是 RNN 那样递归更新隐藏表示。

CNN:让同一种局部模式在不同位置复用

DNN 为不同输入位置学习不同权重。CNN(Google,2015,p. 11)改成:

时间×频率特征图 → 局部卷积 → 更高层模式 → 分类

例如某个音节晚出现了 100 ms,CNN 仍可以用同一个卷积核检测它。

这里增加了两个假设:

但讲义强调了一个很重要的点:参数更少,不代表计算更少。 卷积核虽然共享,仍然要在很多位置反复执行,所以 CNN 可能比 DNN 参数少,却需要更多 FLOPs。这与 ASR 用 CNN 做声学前端的动机一致:先提取局部声音结构,再交给后面的模块整合更大范围的信息。

Attention:让模型学习哪些时间位置更重要

Attention pooling 和 ASR 的解码 attention 有什么不同?

前面的 DNN 先做逐帧判断,再手工平滑。讲义中的 attention-based KWS(Xiaomi,2018,p. 12)则先用 RNN、GRU、LSTM 或 CRNN 编码音频,得到 h₁, …, h_T,再学习怎样汇总整段信息:

eₜ = vᵀ tanh(Whₜ + b)
αₜ = exp(eₜ) / ∑_{j=1}^T exp(eⱼ)
c = ∑_{t=1}^T αₜ hₜ

eₜ 是时间位置的分数,αₜ 是归一化权重,c 是最后送给分类器的上下文向量。比如一秒音频里只有中间一小段包含关键词,模型可以给那一段更大的权重,减少无关背景对汇总结果的影响。

这里的 attention 主要做序列汇总。前面 ASR 的 AED 则在生成每个输出 token 时,根据解码状态选择声学信息,两者用途不同。Attention 也不会自动赋予流式能力:上面的归一化覆盖当前输入的 T 帧,能否在线运行,还要看 encoder、窗口和计算方式是否需要未来信息。

Multihead attention:多个头为什么需要约束?

单个上下文向量可能压缩掉部分信息。多个 attention head 可以各自形成 c₁, …, c_H,再一起用于分类。但多个头也可能学到相似的权重,重复关注同一段声音。

讲义 pp. 13–15 介绍的工作,用正交约束鼓励不同头提取不同信息。把归一化后的上下文向量作为列拼成 C,其中一个正则项的核心形式是:

L_inter ∝ ‖CᵀC − I_H‖²_F

非对角元素表示不同头之间的内积;压低它们,可以减少头之间的冗余。原工作还对 attention score 向量施加头间约束,并鼓励同一头在不同正样本上的上下文保持相似。后者和“不同头彼此不同”是两个方向的约束,不能把所有正则项都理解成越正交越好。

这提供了一种学习偏好,并不保证每个头严格对应一个音素,也不意味着增加头数一定提高准确率。

更轻的结构:时间轴和频率轴要区别对待

MatchboxNet:沿时间做可分离卷积

讲义 p. 16 提醒我们:谱图虽然长得像图片,但两个坐标轴的含义不同。一个局部模式晚出现一点,通常还是相同的声音事件;沿频率轴移动却可能改变音高、谐波或共振峰信息。因此,不能把图像中的平移假设原样搬到所有频带上。

MatchboxNet(NVIDIA,2020,p. 17)沿用 QuartzNet 的设计思路,把频率特征作为输入通道,用 1D time-channel separable convolution 建模时间变化:

逐通道的时间卷积:每个通道先提取时间模式
                  ↓
1 × 1 pointwise 卷积:再混合不同通道的信息
                  ↓
残差块、后续映射与分类

忽略偏置,时间核宽 K、输入通道 C_in、输出通道 C_out 时,普通 1D 卷积参数量为 K × C_in × C_out;depthwise temporal convolution 加 pointwise convolution 为:

K × C_in + C_in × C_out

它把时间模式提取和通道混合拆开,减少参数与乘加运算。实际速度仍取决于设备是否高效支持这些算子、内存访问,以及运行时实现。

SubSpectral Normalization:不同频带分别归一化

SSN(2021,p. 18)把频率轴切成多个子带,在各子带内分别做类似 BatchNorm 的归一化,而不是让所有频带共享同一组统计量。对于 N × C × F × T 的输入,N 是 batch,C 是通道,F 是频率,T 是时间。

它让各频带使用各自的统计量,避免把不同频带的分布直接混在一起,回应的是“频率位置有意义”这一点。SSN 是归一化方法,可以与卷积结构配合使用,本身不负责时间对齐或关键词判决。

BC-ResNet:在一维上计算,再广播回二维

Broadcasted Residual Learning(2021,pp. 19–20)进一步减少在完整时间 × 频率网格上的重复计算。先用 f₂ 提取特征,沿频率轴平均池化,把特征压成时间序列;再通过 f₁ 建模时间变化,最后把结果沿频率轴广播回去。

讲义给出的 BCResBlock 可以写成:

y = x + f₂(x) + BC(f₁(AvgPool_F(f₂(x))))

这里的 BC 是广播操作。时间分支在压缩后的表示上计算,节省成本;保留 f₂(x) 的二维残差路径,则避免所有频率细节都被平均掉。SSN 也出现在讲义展示的 BCResBlock 中,两者可以共同利用频率结构。

Keyword Transformer:用 self-attention 组合片段

Keyword Transformer(2021,p. 21)把 Mel 谱图沿时间切成 patch,展平后投影为 embedding,加入位置信息和 class token,再送入 Transformer encoder,用 class token 的表示分类:

Waveform → Mel 谱图 → 时间片段 → Patch + Position embeddings
                                         ↓
                              Transformer encoder
                                         ↓
                                Class token → 类别

它与前面的 attention pooling 不同:self-attention 让输入片段之间相互交换信息,而不只是最后做一次加权汇总。它能建模较远片段的关系,但标准全局 attention 的成本随 token 数呈二次增长。短词分类上的结果,也不能直接证明它适合持续监听;还要检查窗口长度、缓存和右侧上下文。

把这些结构放在一起,解决的问题就更清楚:

结构主要改变什么
DNN + 平滑局部逐帧判别,再用后处理组合证据
SVDF用低秩分解减少时间 × 特征权重
CNN / MatchboxNet复用局部模式,并通过可分离卷积降低成本
Attention pooling / 多头学习汇总哪些时间位置,并减少头间冗余
SSN / BC-ResNet利用频带差异,减少完整二维网格上的计算
Keyword Transformer让片段通过 self-attention 交换信息

级联系统:为什么不让最大模型一直监听?

一个更准确的模型如果一直运行,可能消耗太多电量。讲义 pp. 24–28 的 Google、Apple 系统把检测拆成多个阶段:

麦克风
  ↓
低功耗处理器:小模型持续检测
  ↓ 仅把候选送到下一阶段
应用处理器:更精确的关键词检查
  ↓
说话人验证(适用时)
  ↓
服务器验证 / ASR → 理解与执行请求

Google 的例子包括端侧 KWS 加服务器验证,以及移动设备上“小检测器 → 更准确的检测器 → 说话人验证”的级联。Apple 2017 年的方案也采用低计算量检测与更大 DNN 的两遍检测。

Apple 2023 年的例子更具体:Always On Processor(AOP)上运行 DNN + HMM;候选音频交给 Application Processor(AP)上的高精度 checker,使用带 CTC 训练目标的 Conformer encoder 和交叉熵训练的 decoder;个人设备还结合 speaker identification,再接后续 ASR。这是课件引用的历史系统设计,不代表所有设备或当前产品都使用完全相同的链路。

这里与 ASR 笔记接上了:CTC 可以为声学序列提供训练信号,而系统最终要回答的仍是“是否出现有效唤醒”,不必把检测器等同于完整转写服务。关键词检查回答“说了什么”,说话人验证回答“是不是目标用户”,两者的拒绝原因不同。

第一级要留住候选,后级负责进一步过滤

级联的收益,是让昂贵计算只发生在少量候选上。若每秒检查 r 次,第一级每次成本是 c₁,候选通过率是 q,第二级每次成本是 c₂,一个简化的平均计算量模型是:

每秒计算量 ≈ r(c₁ + q c₂)

这是帮助理解的近似式,实际还要考虑唤醒处理器、搬运音频和后级运行时长的成本。因此,第一级通过太多背景声音,即使最后都被拒绝,也会增加耗电。

另一方面,前级漏掉的真唤醒不会进入后级。对两级检测,真唤醒通过率为:

P(pass₁, pass₂ | K)
  = P(pass₁ | K) × P(pass₂ | pass₁, K)

其中 K 表示真实关键词事件。第二项是在前级筛选后的候选上计算的条件通过率,不能直接拿两个独立测试集上的准确率相乘。级联通常让前级偏向保留真实候选,再由后级提高精度,但阈值要联合调节,最后评估整条链路的 FRR、FA/hour、延迟与功耗。

真正部署时:让模型持续、稳定地运行

流式缓存:别重复计算同一段历史

假设每次取最近一秒音频,每 20 ms 滑动一次窗口,相邻输入会重叠 98%。如果每一步都重新跑完整网络,就在大量重复计算过去的声音。

讲义 pp. 30–31 的 streaming detection 用缓存复用卷积的历史结果:

新音频 / 新特征到达
        ↓
读取各层仍然有效的历史状态
        ↓
只计算新增位置 → 更新环形缓冲区 → 丢弃过期状态
        ↓
更新关键词分数与触发判断

缓存可能存在于多个层,每层需要保留的状态由卷积核、stride、dilation 和感受野决定。这里要区分三个问题:

不能只给离线模型加一个 buffer,就认为已经变成低延迟模型。若卷积使用未来帧,仍要等待;若归一化或池化依赖完整窗口,也要检查在线执行是否保持原来的输出语义。重复触发的合并规则同样要与事件级评估保持一致。

迁移学习:少量样本能做什么?

讲义 p. 32 的 few-shot 方案,先从 9 种欧洲语言、760 个关键词、约 140 万条样本中学习 embedder,再使用 5 个新目标词样本和预先准备的 128 个非目标样本,适配一个三分类器。在常见设置中,这三类是目标词、unknown 和 background。

关键是先复用已有语音表示,再用少量样本学习新的分类边界。“只用 5 个样本”指新任务的适配阶段,前面已经投入大量预训练数据。 能否迁移到新的语言、口音和设备,仍需要目标场景测试;少样本实验结果不能直接保证任意自定义唤醒词都可靠。

类别不平衡:背景声音占绝大多数

持续监听时,大部分时间都没有唤醒词。一个总输出“没有关键词”的模型可能有很高的窗口 accuracy,却完全不能使用。讲义 p. 33 列出三种训练策略:

单个样本的 focal loss 可以写成:

L_focal = −α_y (1 − p_y)^γ log(p_y)

p_y 是正确类别的预测概率,α_y 是类别权重,γ ≥ 0 控制对容易样本的降权程度。这些策略改变训练信号,不能替代真实背景音测试,也不能保证某个阈值天然满足 FA/hour 目标。

鲁棒性:除了更多正样本,还需要难负样本

课件 p. 34 列出了多任务学习、数据增强、TTS 合成数据、hard negative mining、联邦学习和数据清洗。

数据增强包括 pitch / tempo 变化、时间平移、重采样、房间脉冲响应(RIR)模拟和背景噪声。它们分别扩大音高与语速、出现位置、采集条件和声学环境的覆盖。重采样也要区分是在模拟采集链路,还是不保持时长地改变播放速度,不能默认两者效果相同。

Hard negative mining 则从真实误触发中找出“很像唤醒词但并不是”的音频,例如相近发音、电视对话和其他人的说话,再作为负样本参与训练。它补的是决策边界附近的数据,而不是单纯增加随机噪声。训练挖掘用的录音应与最终测试录音分开,避免把修正已知样本误当成泛化提升。

KWS 还可以和 ASR 共享表示,联合训练:

L = λ L_KWS + (1 − λ) L_ASR,  0 ≤ λ ≤ 1

ASR 提供更细的语音内容监督,KWS 保持对目标检测任务的约束;是否受益取决于数据、损失权重和训练方式。TTS 可以扩展发音与说话人覆盖,但合成语音和真实麦克风录音仍有分布差异。联邦学习改变的是跨设备使用训练数据的方式,数据清洗改善的是标签和录音质量,它们都不会自动解决误触发。

模型优化:参数量、计算量和功耗分别看

课件最后一页列出了几种互补方法:

方法主要作用验证重点
图优化 / 重参数化合并可融合算子,把训练结构转换成更简单的推理图;课件例子为 RepCNN转换后输出与目标硬件上的运行时间
量化降低权重和激活的数值精度,必要时采用量化感知训练(QAT)关键词分数与阈值是否改变,以及精度、延迟和内存
剪枝去掉部分权重或结构;结构化剪枝更容易映射到更小的计算图剪掉的部分是否真的减少设备上的计算
参数共享 / Adapter复用参数,减少新增参数或适配成本减少的是可训练参数、存储,还是实际推理开销
蒸馏用教师模型指导学生模型,尽量保留检测能力学生在相同事件级指标和部署预算下的表现

量化、剪枝等改变模型后,要重新选择工作阈值,验证整条级联。参数更少通常有利于存储,MACs 更低说明理论乘加更少,但持续监听是否省电,还要在目标设备上测运行频率、缓存内存、处理器唤醒与数据搬运成本。

课件与延伸阅读


Share this post on:

下一篇
深度学习音频笔记 4:ASR 的语言、知识与部署