Part 2: 触发字检测
关键词语音唤醒
触发字检测
欢迎来到这个专业课程的最终编程任务!
在本周的视频中,你了解了如何将深度学习应用于语音识别。在本作业中,您将构建一个语音数据集并实现触发字检测算法(有时也称为关键字检测或唤醒检测)。触发字检测技术,可以让亚马逊Alexa,Google Home,Apple Siri和百度DuerOS等设备在听到某个词语时进行唤醒。
本练习中,我们的触发词将是“Activate”。每当它听到你说“Activate”时,它就会发出“chiming”声音。在此作业结束时,您将能够录制自己正在讲话的片段,并在算法检测到您说出“chiming”时让算法触发一次钟声。
完成作业后,也许你还可以扩展到笔记本电脑上运行,这样每当你说“chiming”它启动你最喜欢的应用程序,或打开你家的网络连接灯,或触发一些其他事件。
本作业中,你将学到
- 构建一个语音识别项目
- 合成和处理音频记录以创建训练/开发测试集
- 训练触发字检测模型并进行预测
导包
import numpy as np
from pydub import AudioSegment
import random
import sys
import io
import os
import glob
import IPython
from td_utils import *
%matplotlib inline
1 数据合成:创建语音数据集
首先为触发字检测算法构建一个数据集。 理想情况下,语音数据集尽可能接近您希望运行的应用程序。 在这种情况下,您希望在工作环境(图书馆,家庭,办公室,开放空间等)中检测到“activate”一词。 因此,您需要在不同的背景声音中混合使用正面词语(“activate”)和负面词语(除activate以外的随机词)。 我们来看看如何创建这样一个数据集。
1.1 聆听数据
你的朋友正在帮助你完成这个项目,并且他们已经去过遍布该地区的图书馆,咖啡馆,餐馆,家庭和办公室,以记录背景噪音,以及人们说正面/负面词汇的片段的片段。 这个数据集包括以各种口音说话的人。
在raw_data目录中,您可以找到正面单词,负面单词和背景噪音的原始音频文件的子集。 您将使用这些音频文件合成数据集来训练模型。 “activate”目录包含说“activate”的人的正面例子。 “negatives”目录包含说除“activate”以外的随机单词的反面例子。 每个音频记录有一个词。 “backgrounds”目录包含步同环境下的背景噪音的10s的剪辑。
聆听样例数据
IPython.display.Audio("./raw_data/activates/1.wav")
IPython.display.Audio("./raw_data/negatives/4.wav")
IPython.display.Audio("./raw_data/backgrounds/1.wav")
你将使用这三种类型的音频数据创建标签数据集。
1.2 从录音到声谱图
什么是录音? 麦克风随着时间的推移记录气压的微小变化,正是这些气压的微小变化让你的耳朵感觉到了声音。 你可以想象一个录音是一个长长的数字列表,用于测量麦克风检测到的微小气压变化。 我们将使用以44100赫兹采样的音频。 这意味着麦克风每秒给我们44100个数字。 因此,10秒音频剪辑由441000个数字(= 10×44100)表示。
从这个音频的原始数据表示中找出是否包含“activate”这个词是相当困难的。 为了帮助你的序列模型更容易学习检测触发字,我们将计算音频的谱图。 频谱图告诉我们一段时间内音频片段中存在多少不同的频率。
(如果你曾经学习过信号处理或傅里叶变换上的课程,频谱的计算时通过在原始音频信号上滑动窗口计算的,并使用傅立叶变换计算每个窗口中最活跃的频率。 如果你不理解前面的句子,也不用担心。)
让我们看一个例子:
IPython.display.Audio("audio_examples/example_train.wav")
x = graph_spectrogram("audio_examples/example_train.wav")
上面的图表表示每个频率(y轴)在各个时间步(x轴)上的活动情况。
上图是音频记录的频谱图,其中颜色显示的是不同时间点音频不同频率的程度。 绿色方块意味着音频片段中的某个频率更加活跃(声音更响亮); 蓝色方块表示较少的活动频率。
输出谱图的维度取决于谱图软件的超参数和输入的长度。 在本文中,我们将使用10秒音频剪辑作为我们培训示例的“标准长度”。 频谱图的时间步数将为5511.稍后你会看到频谱图作为输入X给带网络中,因此 Tx T x = 5511。
_, data = wavfile.read("audio_examples/example_train.wav")
print("Time steps in audio recording before spectrogram", data[:,0].shape)
print("Time steps in input after spectrogram", x.shape)
# Time steps in audio recording before spectrogram (441000,)
# Time steps in input after spectrogram (101, 5511)
现在你可以定义:
Tx = 5511 # The number of time steps input to the model from the spectrogram
n_freq = 101 # Number of frequencies input to the model at each time step of the spectrogram
注意: 即使10秒作为我们默认的训练示例长度,也可以将10秒的时间离散为不同的数值。 你已经看过441000(原始音频)和5511(频谱图)。 在前一种情况下,每个时间步代表10/441000≈0.000023秒。 在第二种情况下,每个时间步代表10/5511≈0.0018秒。
对于10s的音频,关键的值有:
- 441000(原始音频)
- 5511= Tx T x (频谱图输出,也是神经网络输入的维度)
- 10000(由pydub模块用于合成的音频)
- 1375= Ty T y (即将构建的GRU的输出时间步的数量)
注意: 每一个样本恰好10秒的时间,被不同类型进行离散化。这些都是超参数,可以更改(除了441000,这是麦克风的功能)。 这里选择了语音系统标准范围内的值。
比如 Ty T y = 1375意味着对于模型的输出,我们将10秒离散成1375个时间间隔(每个长度为10 /1375≈0.0072秒),并尝试预测这些时间间隔是否最近有人说过“activate”。
又如上面的10000这个数字,将10秒剪辑离散化为10/10000 = 0.001秒的间隔。 0.001秒也被称为1毫秒 所以当我们说按照1ms间隔进行离散化时,这意味着正在使用10,000步。
Ty = 1375 # The number of time steps in the output of our model
1.3 生成一个训练示例
由于语音数据很难获取和标记,因此您将使用正向、反向和背景的音频剪辑合成训练数据。 记录大量10秒的随机“activates”音频剪辑是很慢的。 相反,记录大量正向和反向词汇,并单独记录背景噪音(或从免费在线渠道下载背景噪音)更容易。
为了合成一个训练样本,你需要:
- 随机选择一个10秒的背景音频剪辑
- 随机将0-4个正向音频片段插入此10秒剪辑中
- 随机将0-2个反向音频片段插入此10秒剪辑中
因为您已将“activates”一词合成到背景剪辑中,所以您确切知道10秒剪辑中何时出现“activates”。 稍后您会看到,这样也更容易生成标签y⟨t⟩。
您将使用pydub软件包来处理音频。 Pydub将原始音频文件转换为Pydub数据结构列表(这里了解细节并不重要)。 Pydub使用1ms作为离散化间隔(1ms是1毫秒= 1/1000秒),这就是为什么10秒剪辑总是使用10,000步表示的原因。
# Load audio segments using pydub
activates, negatives, backgrounds = load_raw_audio()
print("background len: " + str(len(backgrounds[0]))) # Should be 10,000, since it is a 10 sec clip
print("activate[0] len: " + str(len(activates[0]))) # Maybe around 1000, since an "activate" audio clip is usually around 1 sec (but varies a lot)
print("activate[1] len: " + str(len(activates[1]))) # Different "activate" clips can have different lengths
# background len: 10000
# activate[0] len: 916
# activate[1] len: 1579
在背景上覆盖正面/负面的词语
给定一个10秒的背景剪辑和一个短的音频剪辑(正面或负面的单词),您需要能够将单词的短片段“添加”或“插入”背景。 为确保插入到背景上的音频片段不重叠,需要跟踪以前插入的音频片段的时间。 您将在背景中插入多个正面/负面单词剪辑,并且不希望插入有重叠。
为了清楚起见,当您在咖啡厅噪音的10秒剪辑中插入1秒“activate”时,最终会出现10秒的剪辑,听起来像某人在咖啡厅中说“activate”。你不会以11秒的剪辑结束。 稍后你会看到pydub如何让你做到这一点。
在插入的同时创建标签
回想一下,标签y⟨t⟩表示某人是否刚说完“activate”。给定一个背景剪辑,我们可以初始化所有t的y⟨t⟩= 0,因为该剪辑不包含任何“activate”。
当你插入或覆盖“activate”剪辑时,您还将更新 y⟨t⟩ y ⟨ t ⟩ 的标签,以便输出的50个步骤具有目标标签1.您将训练GRU以检测某人何时说完“激活”。 例如,假设合成的“activate”剪辑在10秒音频中的5秒处结束 - 恰好在剪辑的中途。 回想一下