CMUSphinx文档指南翻译
原文:https://cmusphinx.github.io/wiki/
语音是一种复杂的现象。人们很少理解它是如何产生、如何被察觉到的。一种天真的感觉经常是语音是由单词以及组成音素(phones)的每个单词构成的。而现实却大相径庭。语音是一种动态过程,没有可清晰区分出来的部分。我们可以使用一个声音编辑器,然后看看语音记录,再听一听,这往往很有用。下图是一个语音编辑器中的语音记录的例子。
所有对语音现代化的描述都在一定程度上是概率性的。这意味着在相邻两个单元之间,或在相邻两个单词之间没有某种边界。语音到文本的翻译以及语音的其他应用永远不会100%正确。这个观点对于软件开发者而言很不寻常,软件开发者往往对确定性的系统进行工作。并且这也产生了许多仅特定于语音技术的问题。
在当前实践中,语音结构作如下理解: 语音是一串连续的音频流,它混合了相当稳定的状态与动态改变的状态。在这一系列的状态中,我们或多或少可以定义类似的语音类或音素。我们认为单词用于构成音素,当然这肯定是不正确的。相应于一个音素的一条波形图的声音属性根据许多因素会发生很大改变,比如音素上下文、扬声器、语音类型等等。我们所谓的协同发音使得音素声音与其“所公认的”表示有很大不同。接着,由于在单词之间的迁移比起稳定的区域更富信息量,因此开发者经常谈论双音素(diphones)——两个相继音素之间的音素部分,也就是相邻的两个音素。有时,开发者讨论子音素单元——一个音素的不同子状态。我们往往可以找到不同性质的两到三个领域。 数字三很容易解释:音素的第一部分依赖于其之前的音素,中间部分是稳定的,而下一部分则依赖于后一个音素。这就是为何对于语音识别,一个所选的音素往往有三个状态。 有时音素在某个特定的上下文中进行考虑。在上下文中的这种音素称为三音素(triphones)或平均五音素(quinphones)。比如,在单词"bad"中,"u"的左边音素为"b",右边音素为"d",其发音与单词"ban"稍微有些不同。请注意,与双音素不同,它们在音素波形中的同一范围内匹配。它们仅仅在名字上不同,因为它们描述了稍微不同的声音。 出于计算目的,检测三音素的各个部分而不是三音素作为一个整体是有帮助的,比如,如果你想要创建一个三音素起始的探测器,并且跨多个三音素来共享它。声音探测器的整个种类可以由少量的独立不同的短声音探测器来表示。通常,我们使用4000个独立不同的短声音探测器来合成三音素探测器。我们称那些探测器为森那(senones)。一个森那对上下文的依赖比起只考虑左右上下文要复杂得多。这可能是一颗决策树(decision tree)或是其他方式所定义的一个相当复杂的功能。 接着,音素构建子单词单元,就跟音节一样。有时,音节被定义为“稳定消减的实体”。例如,当语音变快时,音素常常发生改变,但音节仍然是相同的。同时,音节与语调轮廓相关。有其他方式构建子单词——基于形态的(在形态丰富的语言中)或基于音素的。子单词通常用在开放的词汇表语音识别中。 子单词构成单词。单词在语音识别中很重要,因为它们大大限制了音素的结合。如果有40个音素并且平均一个单词具有7个音素,那么一定就有407个单词。幸运的是,即便具有非常丰富词汇量的人在实际使用中也很少使用超过20K的单词。这使得识别更可行。 单词与其他非语言声音,这些非语言声音我们称为填料(fillers)(比如呼吸、嗯、啊、咳嗽声等),形成了发声(utterances)。它们是在语音间歇之间的独立的音频块。它们不需要匹配语句,语句更具有语义概念。 在最顶层,有轮流的对话,不过这些跨越了本文档的目的范围。
识别语音的通常方法如下:我们拿到一条波形,在发声处用静音将它分割,然后设法识别在每个发声中当前正在说的东西。为了要实现这个,我们想要获取所有可能的单词组合,并且设法用音频匹配它们。我们选择最佳的匹配组合。 在此匹配过程中有一些重要的概念。首先,是特征(features)概念。由于参数数量很大,我们需要尽量优化它。从语音所计算出的数量通常被划分为帧。然后对于每一帧,一般具有10ms的长度,我们萃取39个表示该语音。这称为一个特征向量。生成参数个数的方法是当前活跃的学术研究的主题,但在一种简单的情况下,它是来自于频谱的派生物。 第二,它是模型的概念。一个模型描述了某个数学对象,此数学对象收集了说话单词的公共属性。在实践上,对于森那的一个音频模型,它是三个状态的高斯混合——简单来说,就是最有可能的特征向量。从模型的概念出发,会引发以下问题: ⚫︎ 该模型描述现实有多好? ⚫︎ 该模型是否能比此模型内部问题做得更好? ⚫︎ 该模型的适应性如何,如果条件改变的话? 语音模型称为隐马尔可夫模型(Hidden Markov Model)或HMM。它是一个泛型模型,描述了一种黑盒通信通道。在此模型过程中被描述为一系列的状态,这些状态以某种概率相互改变。这种模型目的在于描述任一类似语音的顺序过程。我们已经可以证明HMM对于语音解码真的具有实践性。 第三,它本身是一个匹配过程。由于要与所有模型比较所有的特征向量将花费比宇宙寿命更长的时间,因此我们通过提供许多技巧来做优化搜索。在任何时间点,我们维持最佳匹配版本,并随着时间流逝扩展它们,为下一帧产生最佳匹配版本。
根据语音结构,在语音识别中使用三个模型来做匹配: 一个听觉模型(acoustic model)包含了每个森那的听觉属性。有上下文独立的模型包含这些属性(对于每个音素最有可能的特征向量)以及依赖于上下文的模型(由带有上下文的森那构建)。 一个音素字典(phonetic dictionary)包含了从单词到音素的映射。此映射不是很有效。比如,只有两到三个发音版本在字典中记录。然而,在大部分时候它在实践上是足够了。字典不是将单词映射到音素的仅有的方法。你也可以使用一些从机器学习算法中所学到的复杂功能。 一个语言模型(language model)用于约束单词搜索。它定义了哪个单词可以跟在先前已经识别出的单词之后(记住,匹配是一个顺序过程),并且通过剥去不可能出现的单词来帮助大大约束匹配过程。最最通常的语言模型是N元语法语言模型——这些模型包含了单词顺序的统计,还有有限状态语言模型——这些模型通过有限状态自动化,有时带有权重,定义了语音顺序。这意味着它应该很擅长预测下一个单词。一个语言模型通常约束被认作为它所包含的单词的词汇表。那对于名字识别是一个问题。为了要处理这个问题,一个语言模型可以包含更小的块,类似子单词或甚至是音素。请注意,在这种情况下的搜索空间约束往往更糟,并且相应的识别精确度比起用一个基于单词的语言模型更低。 那三个实体在一个引擎中结合在一起以进行识别语音。如果你打算对其他某个语言应用你的引擎,那么你需要在适当的地方获得这些结构。对于许多语言有听觉模型、音素字典以及甚至大量的词汇表语言模型可进行下载。
一个词格(Lattice)是一个有向图(directed graph),表示识别的各个版本。通常,获得最佳匹配是不实际的。在那种情况下,词格是非常良好的中间格式以表示识别结果。 各个版本的N佳列表(N-best lists)类似词格,尽管其表示不如词格密集。 单词混淆网络(word confusion networks,sausages)也是词格,不过其节点的严格次序从词格边沿获取。 语音数据库(speech databases)——一组来自任务数据库的典型记录。如果我们开发对话i 系统,那么它可能是来自用户所记录的对话。对于字典系统,它可能是在读记录。语音数据库用于训练、调整、以及测试解码系统。 文本数据库(text databases)——对于比如语言模型训练所收集的样本文本。通常,文本的数据库以样本文本的形式进行收集。这种收集的发布是将现有的文档(像PDF、网页、扫描)放入到一个讲话文本形式。也就是说,你需要移除标签和头部信息,扩展其讲话形式的个数以及扩展缩略语。
当我们在开发语音识别时,最复杂的问题是让搜索精确(考虑让许多变体尽可能匹配的情况)并且使它足够快而不至于要跑个好几年。由于模型不是完美的,因此另一个挑战是使模型匹配语音。 通常系统在一个测试数据库上进行测试,用于正确表示目标任务。 我们使用以下指标: 精确度:它与错误率几乎是等同的,但它并不考虑插入。 精确度 = (N - D - S) / N 对于大部分任务,精确度与WER比起来是一种较糟糕的测量,由于插入对于最终结果也很重要。然而对于某些任务,精确度是对解码器性能的一个合理测量。 速度:假设一个音频文件具有2小时的记录时长(Recording Time,简称RT)并且解码需要6个小时。那么此速度被记为3x RT。 ROC曲线:当我们谈论检测任务时,有错误的警告与命中/错失。为了描述这些,我们使用ROC(接收者操作特征:Receiver Operating Characteristics)曲线。ROC曲线是一副描述错误警告个数对命中个数的图。它设法找到最优的点,即错误警告个数很少且命中个数匹配100%。
还有其他我们平时不太关注的性质,但对于许多实践应用来说也很重要。你第一个任务应该构建这么一个测量,并且在系统开发期间系统性地应用它。你第二个任务是收集测试数据库,并测试你的应用程序执行得怎么样。
- 算法
- 已存在的精确结果
- 资源
- 技术
在你开发一套语音应用之前,你需要考虑几个重要的点。它们将定义你实现你应用程序的方式。