① 最后,假设你刚刚插入了"activate." ,则执行代码以更新标签$y^{\langle t \rangle}$。
- 在下面的代码中,由于$T_y = 1375$,所以y是一个 (1,1375)维向量。
② 如果"activate"在时间步骤$t$结束,则设置$y^{\langle t+1 \rangle} = 1$以及最多49个其他连续值。
- 但是,请确保你没有用完数组的末尾并尝试更新 y[0][1375],由于$T_y = 1375$,所以有效索引是 y[0][0] 至 y[0][1374]。
- 因此,如果 "activate" 在1370步结束,则只会得到 y[0][1371] = y[0][1372] = y[0][1373] = y[0][1374] = 1
③ 练习:实现insert_ones()。你可以使用for循环。
- 如果你是python的slice运算的专家,请随时使用切片对此向量化。
- 如果某个片段以segment_end_ms结尾(使用10000步离散化),请将其转换为输出$y$的索引(使用$1375$步离散化),我们将使用以下公式:
- segment_end_y = int(segment_end_ms * Ty / 10000.0)
① 最后,你可以使用insert_audio_clip和 insert_ones来创建一个新的训练示例。
② 练习:实现create_training_example()。你需要执行以下步骤:
- 将标签向量$y$初始化为维度为$(1, T_y)$的零numpy数组
- 将现有段的集合初始化为一个空列表
- 随机选择0到4个"activate"音频剪辑,并将其插入10秒剪辑中。还要在标签向量$y$的正确位置插入标签。
- 随机选择0到2个负音频片段,并将其插入10秒片段中。
① 现在,你可以听听你创建的训练示例,并将其与上面生成的频谱图进行比较。
② 最后,你可以为生成的训练示例绘制关联的标签。
2.4 训练集¶
① 现在,你已经实现了生成单个训练示例所需的代码。
② 我们使用此过程生成了大量的训练集。
③ 为了节省时间,我们已经生成了一组训练示例,如下所示。
2.5 验证集¶
① 为了测试我们的模型,我们记录了包含25个示例的验证集。
② 在合成训练数据的同时,我们希望使用与实际输入相同的分布来创建验证集。
③ 因此,我们录制了25个10秒钟的人们说"activate"和其他随机单词的音频剪辑,并手动标记了它们。
④ 这遵循课程3中描述的原则,即我们应该将验证集创建为与测试集尽可能相似。
⑤ 这就是为什么我们的开发人员使用真实音频而非合成音频的原因。
3. 模型¶
① 现在,你已经建立了数据集,让我们编写和训练关键字识别模型!
② 该模型将使用一维卷积层,GRU层和密集层。
- 让我们加载在Keras中使用这些层的软件包。加载可能需要一分钟。
3.1 建立模型¶
① 这是我们将使用的模型架构。
- 花一些时间查看模型,看看它是否合理。

② 该模型的一个关键步骤是一维卷积步骤(图3的底部附近)。
- 它输入5511步频谱图,并输出1375步,然后由多层进一步处理以获得最终的$T_y = 1375$步输出。
- 该层的作用类似于你在课程4中看到的2D卷积,其作用是提取低级特征,然后生成较小尺寸的输出。
③ 通过计算,一维转换层还有助于加快模型的速度,因为现在GRU只需要处理1375个时间步,而不是5511个时间步。
- 这两个GRU层从左到右读取输入序列,然后最终使用dense+sigmoid层对$y^{\langle t \rangle}$进行预测。
- 因为$y$是二进制值(0或1),所以我们在最后一层使用Sigmoid输出来估计输出为1的机率,对应用户刚刚说过"activate"。
④ 请注意,我们使用的是单向RNN,而不是双向RNN。
- 这对于关键字检测确实非常重要,因为我们希望能够在说出触发字后立即检测到触发字。
- 如果我们使用双向RNN,则必须等待记录整个10秒的音频,然后才能知道在音频剪辑的第一秒中是否说了"activate"。
① 可以通过四个步骤来实现模型:
步骤1:CONV层。
- 使用Conv1D()和196个滤波器来实现,滤波器大小为15(kernel_size = 15),步幅为4。
步骤2:第一个GRU层。
- 要生成GRU层,请使用:X = GRU(units = 128, return_sequences = True)(X)
- 设置return_sequences = True可以确保所有GRU的隐藏状态都被feed到下一层。请记住,在Dropout和BatchNorm层之后进行此操作。
步骤3:第二个GRU层。
- 这类似于先前的GRU层(请记住使用return_sequences = True),但是有一个额外的dropout层。
步骤4:按以下步骤创建一个时间分布的密集层:
- X = TimeDistributed(Dense(1, activation = "sigmoid"))(X)
- 这将创建一个紧随其后的Sigmoid密集层,因此用于密集层的参数对于每个时间步都是相同的。
② 练习:实现model(),其架构如图3所示。
① 让我们输出模型总结以查看维度。
② 网络的输出为(None,1375,1),输入为(None,5511,101)。
- Conv1D将步数从频谱图上的5511减少到1375。
3.2 训练模型¶
① 关键词检测需要很长时间来训练。
- 为了节省时间,我们已经使用你上面构建的架构在GPU上训练了大约3个小时的模型,并提供了大约4000个示例的大型训练集。让我们加载模型吧。
② 你可以使用Adam优化器和二进制交叉熵损失进一步训练模型,如下所示。
- 这将很快运行,因为我们只训练一个epoch,并提供26个例子的小训练集。
3.3 测试模型¶
① 最后,让我们看看你的模型在验证集上的表现。
② 看起来不错!但是,精度并不是这项任务的重要指标,因为标签严重偏斜到0,因此仅输出0的神经网络的精度将略高于90%。
③ 我们可以定义更有用的指标,例如F1得分或“精确度/召回率”。但是,我们不要在这里使用它,而只是凭经验看看模型是如何工作的。
4. 预测¶
① 现在,你已经建立了用于触发词检测的工作模型,让我们使用它来进行预测吧。此代码段通过网络运行音频(保存在wav文件中)。
② 可以使用你的模型对新的音频片段进行预测。
③ 你首先需要计算输入音频剪辑的预测。
④ 练习:实现predict_activates()。你需要执行以下操作:
- 计算音频文件的频谱图
- 使用np.swap和np.expand_dims将输入调整为(1,Tx,n_freqs)大小
- 在模型上使用正向传播来计算每个输出步骤的预测
① 一旦估计了在每个输出步骤中检测到"activate"一词的可能性,就可以在该可能性高于某个阈值时触发出"chiming(蜂鸣)"声。
② 此外,在说出"activate"之后,对于许多连续值,$y^{\langle t \rangle}$可能接近1,但我们只希望发出一次提示音。
③ 因此,每75个输出步骤最多将插入一次铃声。
- 这将有助于防止我们为"activate"的单个实例插入两个提示音。
- 该作用类似于计算机视觉中的非极大值抑制。
④ 练习:实现chime_on_activate()。你需要执行以下操作:
- 遍历每个输出步骤的预测概率
- 当预测大于阈值并且经过了连续75个以上的时间步长时,在原始音频剪辑中插入"chime"
⑤ 使用以下代码将1375步离散化转换为10000步离散化,并使用pydub插入“chime”: audio_clip = audio_clip.overlay(chime, position = ((i / Ty) * audio.duration_seconds)*1000)
4.1 测试验证集¶
① 让我们探讨一下我们的模型在验证集中的两个未知的音频剪辑上表现如何。
② 首先让我们听听两个验证集剪辑。