(以下内容搬运自飞桨PaddleSpeech语音技术课程,点击链接可直接运行源码)
随着人工智能的飞速发展,市场上推出了各式各样的智能设备,AI 语音的发展更是使得语音助手成为各大智能终端设备必不可少的软件。语音是人类与设备最直接的交互方式,不需要和实物接触,可远程操控,对于人们来说是最方便自然的交流方式。
自动语音识别(Automatic Speech Recognition, ASR)是一种将语音转化为文字的技术,是人与机器、人与人自然交流的关键技术之一。ASR 是人与智能设备交互的入口,它的功能就是让设备”听懂“人类的语言,从而能够根据识别到的内容去完成人类想要让它做的事情。
语音唤醒(Keyword Spotting, KWS)是语音识别的入口,如何高效、准确地对用户指令给出反应成为这一技术的最重要的目标。
下图是 IPhone 中 Siri 语音助手的交互示意图,总体上可分为以下三个步骤:
Apple 广告中 Siri 语音助手的交互演示视频。
点击播放
KWS、ASR 和声音检测的关系:
与语音识别 ASR 类似,KWS 可以用传统的 HMM 模型完成建模和识别,模型结构上是也是声学模型加解码器。
基于 HMM 的 KWS 模型和传统 ASR 模型的区别:
在 2014 年的文章 Small-footprint keyword spotting using deep neural networks 中,作者提出了一种基于神经网络加后验概率平滑的 KWS 方法,该方法利用词粒度来建模声学模型,可分为以下四个执行步骤:
在 2017 年的文章 Max-Pooling Loss Training of Long Short-Term Memory Networks for Small-Footprint Keyword Spotting 中,作者提出了一种基于 Max-Pooling Loss 的 KWS 模型训练方法。
这种方法可以看作是从帧级别的训练方式转向段级别的训练方式,如下图所示,蓝色填充的帧是唤醒词,在训练阶段,模型对于唤醒词片段的得分取决于某一帧中的最高的得分;而非唤醒词片段,为了保证所有帧的得分都足够低,则需要关注所有的帧。这种得分可以看作是基于声学得分的 Max-Pooling。
有了这个训练方式,我们直接地对唤醒词进行端到端的建模,具体模型可以采取 RNN-based、CNN-based 和 Attention-based 可对音频特征序列建模的模型。PaddleSpeech 中的 examples/hey_snips 采用了
Multi-scale Dilated Temporal Convolutional 模型,通过 Max-Pooling Loss 的训练方法实现了在 Snips 数据集上的训练和评估。
PaddleSpeech 提供了 MDTC 模型在 Snips 数据集上的从训练到评估的全流程脚本,在此章节中将对一些重要步骤做讲解,如需完整执行训练和评估,可以根据 example 中的文档提示运行脚本,详情请参考:examples/hey_snips/kws0
下载 PaddleSpeech 代码并安装所需依赖:
本教程要求paddlepaddle >= 2.2.2
的环境,并需要 Clone PaddleSpeech Repo的代码(因网络访问问题可能需要等待较长时间,此处直接提供 PaddleSpeech r1.0 分支的代码压缩包):
!unzip work/PaddleSpeech-r1.0.zip
额外依赖:
!pip install scipy resampy soundfile tqdm colorlog pathos dtaidistance sklearn yacs loguru matplotlib
进入 example 目录:
%cd PaddleSpeech-r1.0/examples/hey_snips/kws0/
Snips 数据集需要用户自行申请下载:keyword-spotting-research-datasets
该数据集包含不同英语口音的约 11,000 “Hey Sinips” 的关键词的音频和 86,500(约96小时) 的其他发音的负样本。正负样本的音频均在相同的说话人、录音设备和环境噪音等条件下录制的,防止模型在训练的过程中关注非关键词相关的特征。数据集的切分和具体数量由下表所示:
Train | Dev | Test | ||
---|---|---|---|---|
Positive | Utterances | 5,876 | 2,504 | 25,88 |
Speakers | 1,179 | 516 | 520 | |
max / speaker | 10 | 10 | 10 | |
Negative | Utterances | 45,344 | 20,321 | 20,821 |
Speakers | 3,330 | 1,474 | 1,469 | |
max / speaker | 30 | 30 | 30 |
数据集下载完成后,解压至/PATH/TO/DATA/hey_snips_research_6k_en_train_eval_clean_ter
目录。
修改conf/mdtc.yaml
中的data_dir
为'/PATH/TO/DATA/hey_snips_research_6k_en_train_eval_clean_ter'
,只想数据集目录,配置CUDA_VISIBLE_DEVICES
启动 CPU/单卡/多卡训练。
CUDA_VISIBLE_DEVICES=0,1 ./run.sh conf/mdtc.yaml
针对使用场景和训练样本不均衡问题,通常对 KWS 模型通常关注 False Reject 和 False Alarm 指标。在测试集中,通过对不同的唤醒得分阈值下,对模型的指标进行考察。得到每个阈值的样本判别结果后,可以绘制 DET(Detection Error Tradeoff) 曲线:
在此 example 中,我们考察模型在 False Reject 为每小时1次的前提下,False Alarm 的情况,该数值越小则表示模型越好。在下图的结果中,可以确定唤醒阈值为 0.83,此时的 False Alarm Rate为 0.003559(数据由 example 中训练后的模型得到,重新跑后可能会有细微不同):
通过上述的训练后得到模型的 checkpoint,并确定了唤醒阈值为 0.83,在此通过正负样本两段音频的输入进行预测,感兴趣的朋友也可以尝试自己提供录音音频进行预测(采样率为 16000 的单通道 wave 文件)。
keyword.wav
: 正样本,包含唤醒词 Hey Snips 的发音。non-keyword.wav
: 负样本。import IPython
IPython.display.Audio('/home/aistudio/work/keyword.wav')
IPython.display.Audio('/home/aistudio/work/non-keyword.wav')
加载从上述训练过程中得到的模型参数文件,完成预测模型的加载。
加入 Python Package 的搜索路径。
import os
import sys
sys.path.insert(0, os.path.abspath('../../..'))
sys.path.insert(0, os.path.abspath('../../../audio'))
加载 MDTC 模型,模型结构的参数与 /examples/hey_snips/kws0/conf/mdtc.yaml 保持一致。
import paddle
from paddlespeech.kws.models import MDTC
from paddlespeech.kws.models.mdtc import KWSModel
# Model
backbone = MDTC(
stack_num=3,
stack_size=4,
in_channels=80,
res_channels=32,
kernel_size=5,
)
model = KWSModel(backbone=backbone, num_keywords=1)
kws_checkpoint = '/home/aistudio/work/kws.pdparams'
model.set_state_dict(paddle.load(kws_checkpoint))
model.eval()
通过对测试音频进行特征提取和模型前向计算,获取唤醒得分,并通过对比唤醒阈值得到判别结果。
特征提取的参数与 /examples/hey_snips/kws0/conf/mdtc.yaml 保持一致。
音频加载和特征计算:
import paddleaudio
from paddleaudio.compliance.kaldi import fbank
feat_func = lambda waveform, sr: fbank(
waveform=paddle.to_tensor(waveform).unsqueeze(0),
sr=sr,
frame_shift=10,
frame_length=25,
n_mels=80)
keyword_feat = feat_func(
*paddleaudio.load('/home/aistudio/work/keyword.wav'))
non_keyword_feat = feat_func(
*paddleaudio.load('/home/aistudio/work/non-keyword.wav'))
print(keyword_feat.shape, non_keyword_feat.shape)
获取音频的预测得分:
keyword_logits = model(keyword_feat.unsqueeze(0))
keyword_score = paddle.max(keyword_logits).numpy().item()
print(keyword_score)
non_keyword_logits = model(non_keyword_feat.unsqueeze(0))
non_keyword_score = paddle.max(non_keyword_logits).numpy().item()
print(non_keyword_score)
从阈值( 0.83)和音频的预测得分的比较重容易看出,keyword.wav
判别为唤醒,而 non-keyword.wav
为非唤醒。
[1] https://machinelearning.apple.com/research/hey-siri
[2] Chen, Guoguo et al. “Small-footprint keyword spotting using deep neural networks.” 2014 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP) (2014): 4087-4091.
[3] Wang, Zhiming et al. “Small-footprint Keyword Spotting Using Deep Neural Network and Connectionist Temporal Classifier.” ArXiv abs/1709.03665 (2017): n. pag.
[4] Coucke, Alice et al. “Efficient Keyword Spotting Using Dilated Convolutions and Gating.” ICASSP 2019 - 2019 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP) (2019): 6351-6355.
[5] Hou, Jingyong et al. “The NPU System for the 2020 Personalized Voice Trigger Challenge.” ArXiv abs/2102.13552 (2021): n. pag.
[6] Sun, Ming et al. “Max-pooling loss training of long short-term memory networks for small-footprint keyword spotting.” 2016 IEEE Spoken Language Technology Workshop (SLT) (2016): 474-480.
请点击此处查看本环境基本用法.
Please click here for more detailed instructions.
请关注我们的 Github Repo,非常欢迎加入以下微信群参与讨论:
P.S. 欢迎关注我们的 github repo PaddleSpeech, 是基于飞桨 PaddlePaddle 的语音方向的开源模型库,用于语音和音频中的各种关键任务的开发,包含大量基于深度学习前沿和有影响力的模型。