4. 唤醒引擎的流水线设计:特征提取、VAD、KWS的流水线划分

各位做芯片的朋友,今天我们来聊聊唤醒引擎的流水线。说白了,就是怎么把麦克风进来的原始音频,一步步变成“小爱同学”或者“嘿Siri”这个结果。

我个人习惯把唤醒引擎拆成三个环节:特征提取VAD(语音活动检测)KWS(关键词检测)。这三个环节怎么串起来,怎么切流水线,直接决定了你的芯片功耗能压到多低。

核心观点:流水线划分的本质,是用面积换功耗,用延迟换能效。你想想看,如果所有模块都全速跑,功耗肯定爆炸。但如果能把不干活的部分关掉,那才是低功耗的精髓。

4.1 三级流水线的典型架构

先看一张我画的框架图,把整个流程理清楚。

唤醒引擎三级流水线架构 特征提取 MFCC / FBank 帧长20ms,帧移10ms 数据 VAD 语音活动检测 能量阈值 / 分类器 触发 KWS 关键词检测 DNN / 小模型推理 时钟门控 + 电源域划分:VAD未触发时,KWS模块时钟关闭 功耗占比:~15% 功耗占比:~25% 功耗占比:~60% 注:KWS是功耗大头,必须通过VAD做使能控制

这张图其实已经说得很清楚了。特征提取是常开模块,VAD也是常开的,但KWS必须被VAD唤醒才能工作。为什么?因为KWS跑的是神经网络推理,功耗最大。

4.2 特征提取:流水线的起点

特征提取这块,我建议用硬件加速器来做。为什么?因为FFT和Mel滤波器组计算量固定,而且重复性高,用硬件做比用DSP跑省电得多。

我在项目中遇到过一个问题:一开始用软件做MFCC提取,结果发现光这一项就占了整个唤醒功耗的40%。后来改成硬件加速器,直接降到12%。

经验之谈:特征提取的帧长和帧移要跟VAD对齐。我个人习惯用20ms帧长、10ms帧移。这样VAD每10ms判断一次,KWS每帧推理一次,节奏刚好。

特征提取的输出是什么?一般是40维的FBank特征或者13维的MFCC。嗯,这里要注意:FBank保留的信息更多,适合DNN做KWS;MFCC压缩更狠,适合传统GMM模型。现在主流方案都选FBank。

4.3 VAD:流水线的守门员

VAD这个模块,说白了就是判断“现在有没有人说话”。如果没人说话,后面的KWS直接睡大觉。

VAD的实现方式有两种:

  • 传统能量法:计算短时能量和过零率。优点是简单、功耗极低;缺点是容易把空调声、风扇声误判成语音。
  • 轻量级DNN法:用一个小型二分类网络。优点是准确率高;缺点是功耗比能量法高一些。

我个人更倾向于混合方案:先用能量法做粗筛,如果能量超过阈值,再启动DNN做精判。这样既保证了低功耗,又避免了误唤醒。

避坑指南:我曾经在一个项目中,VAD阈值设得太低,结果KWS被频繁唤醒,功耗直接翻倍。后来把阈值调高了一点点,误唤醒率降了80%,功耗也下来了。阈值调校是个细活,一定要结合实际场景反复测。

4.4 KWS:流水线的核心

KWS是功耗大头,也是整个唤醒引擎的终点。KWS的流水线设计,核心在于模型量化计算复用

先看一个典型的KWS推理流程:

// 伪代码:KWS推理流水线
for each frame (10ms间隔):
    // 步骤1:从FIFO读取特征
    feature = read_feature_buffer();
    
    // 步骤2:DNN前向推理
    // 这里用8bit量化,避免浮点运算
    score = dnn_inference_quantized(feature);
    
    // 步骤3:后处理 + 阈值判断
    if (score > THRESHOLD):
        generate_wakeup_interrupt();
    
    // 步骤4:状态更新(用于平滑)
    update_state_machine(score);

这里有个关键点:KWS的推理频率是10ms一次。也就是说,每秒要跑100次推理。如果每次推理都全量计算,功耗肯定扛不住。

我建议的做法是:

  • 权重共享:相邻帧的特征有大量冗余,可以复用上一帧的部分中间结果。
  • 渐进式推理:先算浅层网络,如果得分太低,直接跳过深层计算。
  • SIMD加速:用硬件SIMD指令并行处理多个乘加运算。

数据说话:在我的一个项目中,采用8bit量化 + 权重共享后,KWS的功耗从原来的3.2mW降到了0.8mW。而唤醒率只下降了0.5%。这个trade-off非常划算。

4.5 流水线的时钟与电源管理

流水线划分完了,怎么控制时钟和电源?我总结了一个表格:

模块 时钟域 电源域 工作模式 唤醒条件
特征提取 常开时钟(低频) 常开电源 始终工作
VAD 常开时钟(低频) 常开电源 始终工作
KWS 门控时钟(高频) 可关断电源域 VAD触发后唤醒 VAD输出为语音

你看,特征提取和VAD跑在低频时钟上,功耗本身就低。KWS跑在高频时钟上,但平时是关掉的。只有VAD检测到语音时,KWS才被唤醒。

一个小技巧:KWS被唤醒后,不要立刻全速跑。我习惯先让KWS跑一个快速预判,用最简单的几层网络快速过滤掉非关键词。如果预判通过,再跑完整推理。这样能再省30%的功耗。

4.6 我踩过的坑

最后分享一个真实案例。有一次我做智能音箱的唤醒芯片,流水线划分得很完美,仿真功耗也很漂亮。结果一上板实测,功耗比仿真高了40%。

排查了很久才发现问题:VAD的唤醒信号到KWS的时钟开启之间,有大约5微秒的延迟。这5微秒里,KWS的寄存器状态不确定,导致第一次推理结果全是乱码,然后触发了一次误唤醒。

后来我在VAD和KWS之间加了一个握手信号,确保KWS的时钟稳定后再开始推理。问题就解决了。

嗯,这种细节在仿真里很难发现,只有实际跑起来才知道。所以我的建议是:流水线设计一定要留出足够的时序余量,尤其是跨时钟域的信号同步。


公众号:蓝海资料掘金营,微信deep3321