在本文中,我们提供了一个用于训练语音识别的RNN的简短教程,其中包含了GitHub项目链接。
作者:Matthew Rubashkin、Matt Mollison 硅谷数据科学公司
在SVDS的深度学习研发团队中,我们调研了循环神经网络(RNN)在探究时间序列和提升语音识别性能上的应用。现在很多产品依赖带循环层的深度神经网络,包括谷歌、百度以及亚马逊等公司的产品。
然而,当我们研发自己的RNN工作流程时,我们没有发现像语音识别(利用神经网络做序列学习应用)那样简单而直接的案例。很多案例虽然功能强大,但是相当复杂,例如在Mozilla公共授权下Mozilla积极发展的 DeepSpeech 项目,太过简单抽象,不能用于真实数据。
本文将提供一个简短的教程,用于训练语音识别的RNN;教程包含了全部代码片段,你可以找到相应的 GitHub 项目。
我们正在使用的软件,就是从这个开源项目的代码而来。1906 Edison Phonograph advertisement(1906年爱迪生留声机广告)上的机器语音识别就是一个例子。
这个视频包含了声音振幅的运动轨迹、提取的光谱图及预测文本
根据以往丰富的python使用经验,我们选择用一个经过多年发展且非常成熟完整的软件包:TensorFlow。开始之前,如果你对RNN还不了解,我们强烈推荐你阅读Christopher Olah的一篇有关 RNN长短期记忆网络的综述文章。
语音识别:音频与转录
在2010年之前,语音识别模型最先进的技术是基于语音的方法,包括语音、声学和语言模型的独立组件。过去和现在的语音识别均依赖于利用傅里叶变换,将声波分解成频率和振幅,产生如下图所示的声谱图。
为传统语音识别流水线,训练隐马尔可夫模型(HMM)的声学模型,需要语音+文本数据以及从词到语素的字典。HMM是循序数据生成的概率模型,用于测量字符串差异的字符串度量标准,一般使用 Levenshtein word error distance 进行评估。
这些模型可以简化,并能够通过与音素转录对齐的语音数据变得更精确,但是这是一个乏味的人工作业。相较于word-level (词级)副本来说,phoneme-level (音素级)副本不太可能存在大量的语音数据。
如果你想了解更多现存的开源语音识别识别工具和模型的信息,请查看我们的同事Cindi Thompson近期的文章(recent post)。
联结主义的时序分类(CTC)损失函数
在神经网络做语音识别时,使用允许 character-level (字符级)副本预测的目标函数:联结主义时序分类 Connectionist Temporal Classification (CTC),我们可以抛弃音素的概念。
简单来说,CTC能够计算多序列的概率,这里的序列是指所有可能的语音样本 character-level (字符级)副本集合。网络运用目标函数,让字符序列的可能性最大化(即选择概率最大的副本),并计算预测结果(相对于实际副本的)误差来更新network weights(网络权值)。
值得注意的是,CTC损失函数使用的character-level(字符级)误差不同于传统语音识别模型通常使用的Levenshtein word error distance。对于字符产生的RNN模型而言,字符与词的编辑距离在语音语言(例如 Esperonto 和 Croatian)中是相似的,语音语言中不同的声音有不同的字符。相反,对于非语音语言(例如英语),字符和单词的误差会非常不一样。
如果你想了解更多关于CTC的内容,有很多论文和博文可查。我们将使用TensorFlow的CTC实现,也会继续研究和改进与CTC相关的各种实现,例如这篇来自百度的文章。为了利用传统语音识别或者深度学习语音识别模型算法,我们的团队为模块化和快速原型设计搭建了语音识别平台:
数据的重要性
毫无疑问,创建一个语音转文字表述的系统需要(1)数字音频文件和(2)文字的副本。因为模型应该适用于解码任何新的语音样本,所以系统中我们能够训练的样本越多,模型的表现就会越好。
我们调研了可免费获取的英语语音录音,我们用来训练的一些样本是 LibriSpeech(1000 小时),TED-LIUM(118 小时)和VoxForge(130 小时)。
表格展示了这些数据的具体信息包括总时长,采样率和注释
为了方便使用数据源的数据,我们把所有数据存成扁平格式。每个数据的扁平格式都有一个单一的“.wav”文件和“.txt”文件。
例如,你可以在我们的 Github 项目中找到 Librispeech 训练数据集中的 “211-122425-0059” 数据对应文件:211-122425-0059.wav 和 211-122425-0059.txt。
这些数据文件名称使用一个数据集对象类加载到 TensorFlow 图中,这样会帮助TensorFlow有效加载和处理数据,并且将独立的分片数据从 CPU 加载到 GPU 内存中。下面展示的是数据集对象中数据领域的一个例子:
特征表示
为了让机器识别语音数据,首先必须将这些数据从时域转化到频域。这有好几种方法来创建语音的机器学习特征,例如通过任意的频率分级(例如,每100赫兹),或者通过使用人耳能够听到的频率波段分级。
这种典型的以人为中心的语音数据转换是计算梅尔频率倒谱系数(MFCC),有13或者26种不同的倒谱特征,可以作为这种模型的输入。经过这种转换,数据被存储在一个频率系数(行)随时间(列)的矩阵中。
因为语音不会孤立地产生,并且也没有与字符的一一映射,我们可以通过在当前时间之前和之后捕获声音的音频数据重叠窗口(10 毫秒)上训练网络来捕捉共同作用的影响(一个声音影响另一个声音的发音)。下面是如何获取 MFCC 特征,和如何创建音频数据的窗口的示例代码如下:
对于我们的 RNN 示例来说,我们使用之前的9个时间分片和之后的9个时间分片,每个窗口总攻19个时间点。倒谱系数26的情况下,每 25 毫秒会有 494 个数据点。依赖于数据的采样率,我们建议对于 16000 赫兹使用 26 个倒谱特征, 8000 赫兹使用 13 个倒谱特征。如下是在 8000 赫兹数据上数据加载窗口的示例:
关于 RNN 的语音识别从转换模拟声音到数字声音,如果你想了解更多,可以查看 Adam Geitgey 的机器学习博客。
语音的序列性建模
长短时记忆(LSTM)层是一种循环神经网络(RNN)结构,用来对有长程依赖的数据进行建模。这对时间系列的数据非常重要,因为它们从根本上记住了当前时间点的历史信息,这个历史信息影响结果的输出。
这种上下文对语音识别来说是有效的,因为它的时态特征。如果你想要知道 TensorFlow 中 LSTM 单元是如何实现的,下面展示了深度语音启发的双向神经网络(BiRNN)中 LSTM 层的示例代码。
关于这种网络结构的详细信息,有些非常好的关于 RNN 和 LSTM 如何工作的概述。此外,还有关于替代使用 RNN 进行语音识别的研究,如相比 RNN 计算使用卷积层会更加高效。
网络训练与监控
我们使用Tensorflow训练网络,这样既可以显示计算图,也可以使用 TensorBoard从web门户网站上花很少的额外精力来监视训练 、验证以及测试性能。运用Dandelion Mane在2017年Tensorflow发展峰会上做的精彩演讲(great talk )中提到的技巧,我们使用tf.name_scope来增加节点和层名,并将总结写到文件中。
这样做的结果是自动生成的、可理解的计算图,例如下面的例子——双向神经网络(BiRNN)。数据在左下方到右上方的不同操作间进行传递。为清晰起见,可以为不同的节点做标注,并使用命名空间对节点进行着色。在本实例中,青色的‘fc’盒子对应全连接层,而绿色 的'b'和‘h’盒子分别对应偏移量和权重。
我们使用TensorFlow提供的 tf.train.AdamOptimizer (Adam优化器)来控制学习率。AdamOptimizer通过使用动量(moving averages of the parameters(参数的移动平均值))在传统梯度下降法上有了改进,这促进了超参数的有效动态调整。我们可以通过创建标签错误率的摘要标量来跟踪损失和错误率:
怎样改进RNN
既然我们已经创建了简单的LSTM RMM网络,那么,我们怎么来降低错误率呢?对于开源社区来说,幸运的是,很多大公司都公布了他们性能最佳的语音识别模型背后的数学模型。
2016年9月份 ,微软在 arXiv上发表了一篇论文,该文描述了他们是怎样在NIST 200 Switchboard数据上获得6.9%的错误率的。他们在卷积+递归神经网络顶端使用了几种不同的声学和语言模型。微软团队和其他研究院在过去4年里所做的几项关键改进包括:
值得注意的是,在过去几十年的传统语音识别模型中起先锋作用的语言模型,再次证明其在深度学习语音识别模型中也是有价值的。
改进来自:A Historical Perspective of Speech Recognition, Xuedong Huang, James Baker, Raj Reddy Communications of the ACM, Vol. 57 No. 1, Pages 94-103, 2014
训练你的第一个RNN
我们提供了一个 GitHub项目(GitHub repository),该项目的脚本提供了一个用RNNs和CTC损失函数(在TensorFlow中),训练端到端语音识别系统的简单易行执行方案。GitHub库中包含了来自LibriVox 语料库(LibriVox corpus )示例数据,这些数据被分为如下几个文件夹:
当训练这几个示例时,你会很快注意到训练数据会过度拟合(overfit),使得错词率(WER)约为0%,而测试集和Dev数据集的WER大约能达到85%。测试错误率之所以不是100%,是因为在29个可能的字符选择(a-z,省略号,空格键,空白),网络将很快学习到:
在GitHub库中使用默认设置做训练,运行结果如下图所示:
如果你想训练一个高性能模型,你可以在这些文件夹中添加额外的.wav和.txt文件,或者创建一个新的文件夹,并更新`configs/neural_network.ini` 以及文件夹位置。值得注意的是,即使有强大的GPU,在仅仅几百个小时的音频上做处理和训练也需要非常大的计算能力。