如何训练壹个简单的音频识别网络 如何训练一个人

这篇文章小编将将一步步给你展示,怎样建立壹个能识别10个不同词语的基本语音识别网络。你需要了解,真正的语音和音频识别体系要复杂的多,但就像图像识别领域的MNIST,它将让你对所涉及的技术有个基本了解。
完成本教程后,你将拥有壹个模型,能够辨别壹个1秒钟的音频片段是否是无声的、无法识别的词语,或者是“yes”、“no”、“up”、“down”、“left”、“right”、“on”、“off”、“stop”、“go”。你还可以运用这个模型并在Android应用程序中运行它。
注:这篇文章小编将含有大量代码,需要代码原文的同学请参考文末来源地址中的内容。
准备职业
确保你已经配置了TensorFlow,由于脚本程序将下载超过1GB的训练数据,你需要畅通的网络连接,而且你的机器需要有足够的空余空间。训练经过本身也许需要多少小时,因此确保你有一台可以运用这么长时刻的机器。
训练
开始训练前,在TensorFlow 源码树下运行:
这个脚本程序将开始下载“语音命令数据集”,包括65000条由不同的人说30个不同词语组成的WAVE音频文件。这份数据由Google收集,并在CC-BY协议许可下发行,你可以通过贡献自己五分钟的声音来帮助提高它。这份文件大致超过1GB,因此这部分也许需要一段的时刻,但你应该看一下经过日志,一旦它被下载一次,你就不需要再进行这一步了。
这表明初始化进程已经完成,循环训练已经开始,你将看到每一次训练产生的输出信息。这里分别解释一下含义:
在100步之后,你将会看到一行输出如下:
就可以从该点从头开始脚本。
混淆矩阵
在400步之后,将记录如下的信息:
第一部分是混淆矩阵。为了领会它的含义,首先需要了解所运用的标签,它们是 “silence”、 “unknown”、 “yes”、 “no”、 “up”、 “down”、 “left”、 “right”、 “on”、 “off”、“stop”和“go”。每一列代表一组被预测为某个标签的样本,因此第一列代表着全部预测为“silence”的片段,第二列都被预测为“unknown”词,第三列是“yes”,以此类推。
每一行代表着正确的、完全真正为该标签的片段。第一行是全部为“silence”的片段,第二行的片段都是“unknown”词,第三行是“yes”,以此类推。
这个矩阵比单单壹个准确率更有用,由于它能很好地拓展资料出网络所犯的错误。在这个例子中,除了第一项之外,第一行中的全部项都是零。由于第一行指的是全部实际上是“silence”的片段,这意味着没有壹个被否定地标记为词语,因此大家没有漏报壹个“silence”。这表明网络已经能够很好地区分“silence”和词语。
然而,如果大家看一下第一列,就会看到很多非零值。列代表全部被预测为“silence”的片段,因此除第一项之外的正数都是错误的。这意味着一些真正发声的词语实际上被预测为“silence”,因此大家存在一些误报。
壹个最佳的模型会产生壹个混淆矩阵,其中全部项都是零,除了通过中心这条对角线。通过该玩法发现偏差,可以帮助你弄清楚模型是怎样混淆的,一旦你发现了难题,你就可以通过添加更多的数据或清理类别来化解这些难题。
验证
在混淆矩阵之后,你会看到一行信息如下:
把数据分为三份是很好的行为。最大一份(在这个例子中大约数据的80%)是用来训练网络,较小(这里用10%,作为“验证”)的一份保留用于评估训练经过中的准确率,另一份(最后的10%,作为“测试”)用于在训练完成时评估准确率。
划分数据是由于网络会在训练经过中记录输入,这是有风险的。通过将验证集分开,你可以确保模型在从未运用过的数据上运行。测试集一个额外的保障,以确保你在调整模型经过中没有同时运行训练集和验证集,也没有更大量的输入。
训练脚本自动将数据集划分为这三类,上述日志行展示了模型在验证集上运行的准确率。理想情况中,这个值将和训练集准确率特别接近。如果训练集准确率上升的同时验证集准确率没有上升,这意味着出现过拟合,你的模型仅仅只在训练集上进修,并没有推广到更广泛的玩法中。
Tensorflow的可视化工具
可视化训练经过的壹个好方式是运用tensorboard。该脚本默认将事件保存到/tmp/retrain_logs,你可以通过输入命令行来加载:
在浏览器输入“http://localhost:6006”,你将看到一些展示训练经过的图表。
结束训练
经过多少小时的训练(取决于机器的速度),脚本将完成了全部18000个流程。它将打印壹个最终的混淆矩阵,连同壹个准确率,这些都是在测试集上运行得到的。运用默认配置,你将得到85%~90%之间的准确率。
由于音频识别在移动设备上特别有用,接下来大家将把它导出到压缩包,使得它能够在这些平台上运用。为此,运行命令如下:
一旦压缩后的模型建好,你可以运行label_wav.py脚本来测试,如下:
它将输出三个标签:
希望“left”是顶尖分,指的是正确的标签,但由于训练是随机的,它也许不是你测试的第壹个文件。在同壹个文件夹中测试一些其他WAV文件,看看结局怎样。
分数将在0到1之间,值越高意味着模型对预测越自负。
在Android应用里运行模型
如果你想观察模型在实际应用中表现怎样,最简单的方式就是下载并在你的手机中配置已构建好的Android示范应用了。你可以在你的应用列表找到名为“TF Speech”的应用,打开应用,它会展示和大家刚刚训练模型所用相同的动作词列表,选择“Yes”或者“No”开始。一旦你给予app运用手机的权限,你就可以说一些词,看看是否被模型识别出来并在UI高亮显示。
你也可以自己来构建这个应用程序,由于它是开源代码而且在github的TensorFlow存储库中可调用。默认情况下,它会从tensorflow.org下载壹个预先训练的模型,但你可以轻松地用自己训练的模型替换它。如果这样做的话,你需要确保主要的SpeechActivity Java源文件(如SAMPLE_RATE和SAMPLE_DURATION)中的常量和你在进行训练时对默认值进行的更改相匹配。 你还可以看到壹个Java版本的RecognizeCommands模块和本教程中的C ++版本特别相似。 如果你因此调整了参数配置,可以在SpeechActivity中进行更新,以获取和你的服务器测试相同的结局。
示范app会根据你在压缩图形旁复制的标签文这篇文章小编将件自动更新其用户界面列表,这意味着你可以轻松地尝试不同的模型,而无需进行任何代码更改。如果你更改了途径,则需要更新LABEL_FILENAME和MODEL_FILENAME以指给你新添加的文件。
这个模型是怎样运作的?
本教程运用的体系结构是基于《用于小尺寸决定因素字检测的卷积神经网络》一文中的部分描述。选用它的缘故是其相对简单,可快速训练和易于领会,而不是技术的先进性。建立神经网络模型以处理音频有许多不同的方式,包括反复网络或扩张(无序)卷积等。而本教程基于的卷积网络则对于运用图像识别的人来说特别熟悉。这乍一听似乎有点让人惊讶,毕竟音频是跨越时刻的一维连续信号,而不是2D的空间难题。
如果你打开/tmp/spectrogram.png,你将看到:
不同于时刻从左给右的常规频谱图,由于TensorFlow的记忆顺序,图像中的时刻是从上到下增加的,频率从左到右。你应该可以看到多少明显不同的部分,第壹个音节“ha”明显不同差异于和“ppy”。
由于人耳对某些频率比其他频率更敏感,因此在语音识别中,惯用的方式会是针对该特性做壹个进一步的处理,将其转换为一组Mel-Frequency倒谱系数,简称为MFCC。这也一个二维的单通道显示,因此它可以被看作是图像。如果你针对的是一般声音而不是语音,你会发现你是可以跳过此流程并直接在频谱图上操作的。
接下来,由这些处理流程产生的图像会被输入到多层卷积神经网络,其含有壹个全链接层后以分类器小编觉得。 你可以在tensorflow / examples / speech_commands / models.py中看到此部分的定义。
精度流
大多数音频识别应用程序需要在连续的音频流上运行,而不是单独的剪辑段。在这种环境中运用模型的典型方式是在不同的偏移时刻上重复应用它,并在短时刻内平均结局以产生平滑的预测。如果你将输入视为图像,它则会沿着时刻轴不断滚动。大家想要识别的词可以随时开始,因此需要采取一系列的快照来在提供给模型的时刻窗口中捕获大部分的话术。如果大家以足够高的速度进行采样,那么是很有也许在多个时刻窗口中捕获该单词的,因此将结局进行平均可以进步预测的整体信度。
有关怎样在流式传输数据上运用模型的示例,可以查看test_streaming_accuracy.cc。 它运用了RecognizeCommands来运行长格式输入音频,以尝试查找单词,并将这些预测和标签和时刻的完全真值列表进行相对。这使它成为将模型应用到音频信号流的壹个很好的例子。
你需要壹个长音频文件和显示其中每个单词被说出位置的标签来做测试。如果不想自己录制,可以运用generate_streaming_test_wav实用程序生成一些合成的测试数据。默认情况下,该程序将创建壹个10分钟的.wav文件,文件的词频基本上是每三秒壹个,同时提供壹个包含了每个单词被说出位置的完全真值文这篇文章小编将件。词汇选自当前数据集的测试部分,并和背景噪声混合。想要运行它,请运用
这将保存壹个.wav文件/tmp/speech_commands_train/streaming_test.wav,
并提供壹个包含标签的文这篇文章小编将件在
运行精度测试:
这部分程序将输出正确匹配的词数,有几许词语被给出了错误标签,以及没有真正的词语被说出时模型却被触发的次数。这里有各种参数可以控制信号平均的职业原理,包括--average_window_ms,它配置用以结局平滑的时刻长度,--sample_stride_ms,是模型应用程序之间的时刻,--suppression_ms,用以配置在找到第壹个词后再次触发后续检测的间隔时刻,以及--detection_threshold,它控制给出肯定性预测的平均得分的阈值。
你会看到精度流输出三个数字,而不仅仅是训练中运用的壹个度量。这是由于不同的应用程序有不同的标准,一些能够忍让频繁的不正确结局,只要最终找到真正的单词即可(高查全),而另一些则特别专注于确保预测的标签是高也许正确的,即使一些词语并没有被监测出来(高精度)。该工具输出的数值会让你了解到你的模型在应用程序中的表现性能,基于此你可以尝试调整信号平滑参数来调优其性能。要了解你的应用程序的正确参数,可以查看生成的ROC曲线来帮助了解平衡。
识别命令
精度流工具运用了壹个简单的解码器,该解码器被包含在壹个叫做识别命令的小型C ++类中。这个类随着时刻推移运行TensorFlow模型的输出,对信号进行平均,当有足够的证据认为已经找到识别单词时,返回标签信息。它的执行很简单,只需跟踪最后多少预测值并对其进行平均,因此可以根据需要轻松地移植到其他平台和语言上。例如,在Android上的Java或Raspberry Pi上的Python上执行类似的操作都很方便。只要这些算法执行上具有相同的逻辑,就可以运用流测试工具调整控制平均值的参数,接着将其传输到应用程序以获取类似的结局。
高阶训练
培训脚本的默认配置旨在于较小的文件中生成良好的端到端结局,但其实有很多选项可以更改,你可以根据自己的标准自定义结局。
自定义训练集
默认情况下,脚本程序将下载Speech Commands dataset数据集,但你也可以提供自己的训练数据。为了在自定义数据上做训练,你应该确保每个识别目标单词至少有几百个录音,并按类别归入文件夹。例如,如果你想从猫叫声中识别狗叫声,需要先创建壹个名为animal_sounds的根文件夹,接着将其中的两个子文件夹命名为bark(狗叫)和miaow(猫叫)。最后,将音频文件分类放入相应的文件夹中。
将脚本配置为指给新的音频文件夹,需要配置--data_url= to disable downloading of the Speech Commands dataset(关掉下载Speech Commands dataset), 并配置--data_dir=/your/data/folder/,从而找到你新建的音频文件。
这些文件本身应该是16位小端PCM编码的WAVE格式。采样率默认为16,000,但只要全部音频的速率保持一致(脚本不支持重复采样),你可以运用--sample_rate更改此参数。剪辑段也应该采用大致相同的时刻区段。默认的预期时刻区段为1秒,但也可以运用--clip_duration_ms进行配置。如果在开始时一些剪辑段有不同数量的静音时刻,可以查看编辑工具来标准化它们(这是一种快速却投机的方式)。
要注意的壹个难题是,你也许会在数据集中重复相同的声音,如果它们分布在训练,验证和测试集中,则也许会产生有误导性的指标表现。例如,“语音命令”集中含有壹个人多次重复的相同单词。这些重复中的每壹个都也许和其他重复等于接近,因此如果在训练时过度匹配且对其中其中一个进行记忆,那么在测试集中看到特别相似的副本时,它也许表现出不切实际的好。为了避免这种风险,“语音命令”会尽力确保将单个人说出的同壹个单词的全部剪辑放入同一分区。
基于片段名称的哈希值,会将片段分为训练集,测试集,以及校验集。那么在有新的片段加入时也可以保证集中的平稳划分,避免任何训练样本迁移到其他集中。为了保证全部说话人的声音都在同样的类别内,在运用哈希函数计算分配时会忽略“非哈希”之后的文件名。即就是,如果你有两个文件,命名分别为pete_nohash_0.wav和pete_nohash_1.wav,这两个文件将会被分配到同一数据集。
不确定类型
在运用你的应用时,很也许听到一些不在训练集范围内的声音,你会希望模型可以在这些情况下标记出那些它无法识别的噪音。为了帮助神经网络进修需要忽略哪些声音,你需要准备一些不属于你的预测类型的音频片段。如何做呢?你可以创建“呱呱”“噜噜”“哞哞”等子文件夹,接着将你的用户也许碰到的其他动物的声音混入子文件夹。--wanted_words参数对应的脚本定义了你所关心的类型,全部上述子文件中的声音会用来在测试中混入_unknown_的类型。语音命令数据集中含有二十种未知类型,包含了从0到9的数字,和一些随机的命名,例如“sheila”。
默认情况下,测试数据的10%是来自于未知类型,然而你可以通过参数--unknown_percentage来进行调整,增加这个值可以使模型更好的区分未知和预测的声音,然而如果这个数值过大也许会适得其反,由于模型会为了安全而将全部的声音都归类到未知类型!
背景噪音
真正的应用需要在有噪音的环境中进行语音识别。为了使模型在干扰下具有良好的鲁棒性,大家需要对具有相似属性的录音进行训练。语音命令数据集中的文件不是来自录音室,而是用户在不同的环境中通过不同设备获取的录音,这在一定程度上可以增强训练的真正性。除了这些之后,你可以在输入端混合一些随机的环境音频。在语音命令数据集中有壹个独特的文件夹“_background_noise_”(背景噪音),其中包含了数分钟的白噪音和机器的声音,以及日常家务的活动主题的录音。
背景噪音文件的小片段是随机选择,接着在训练中以壹个较低的音量混入音频片段中。这些文件的音量也是随时选择的,通过--background_volume(背景音量)参数进行控制,0是静音,1是最大音量。不是全部的片段都需要添加背景噪音,--background_frequency(背景噪音频率)可以控制背景噪音混入的比例。
你的应用程序也许运行在某种特定的环境下,具有不同的背景噪声玩法,而不是默认的这些,因此你可以在_background_noise_(背景噪音)文件夹中添加自己的音频片段。这些片段应该保持和主数据集相同的采样率,但持续时刻要更长,这样可以从它们中选择一组较好的随机片段。
静音
在大多数情况下,你关心的声音是断断续续的,因此了解啥子时候没有匹配的音频是很重要的。为了支持这一点,大家运用独特的_silence_(静音)标签来标志模型没有识别出有用信息。由于在真正的环境中从来没有完全的静音情形,实际训练时,大家必须提供一些安静的和一些不相关的音频。为此,大家运用_background_noise_(背景噪音)文件夹,这些音频也被混在真正的剪辑,从中选择一些段的音频数据接着标记它们的类型为_silence_(静音)。默认情况下训练集的10%的数据来自该文件夹中,然而,--silence_percentage(静音比例)可以用来控制静音文件的混入比例。和未知类型音频相同,比例的调整是以假阴性作为代价,如果配置的比例越高,模型会将更多的声音配置为静音类型,然而如果比例过高,就会使模型陷入倾给于预测是静音类型的困境。
时刻推移
在训练中增加背景噪音是一种有效的方式来扩大数据集和增加整体的准确性,时刻推移也可以起到同样的影响。这包括了对训练样本数据进行随机的时刻抵消,在音频的开始或者结束会有壹个小片段被切除,并以0进行填充。在训练集的开始阶段运用这种方式来模拟真正的变化,并通过--time_shift_ms参数来进行控制,默认值是100毫秒。增大这个值可以为训练集提供更多的变化,然而会增加切除音频重要部分的风险。还可以运用时刻收缩和音量缩放来实现真正的扭曲,从而扩大数据集,但这两种方式超出了本教程的范围。
自定义模型
这个脚本对应的模型等于大,每次的推算都运用了超过8亿次的浮点运算以及94万个权重参数。这在台式机或现代的手机上会以有限的速度运行,然而由于太多的计算使得在现有设备有限的资源下很难有壹个较高的交互速度。为了支持这些运用场景,大家提供了多少可用的替代方法。
low_latency_conv参数基于神经网络少量决定因素词识别论文中描述的拓扑'cnn-one-fstride4'。准确度相对于卷积要低一些,然而权重参数的数量基本相同,更重要的是每次预测只需要1.1亿浮点运算,很大的提高了运行速度。
你可以在命令行中运用--model_architecture=low_latency_conv来设定运用这种模型。同时,需要更新训练集的进修率以及训练的次数,整体的代码如下:
代码中设定了训练的迭代次数为20,000,进修率为0.01,接着将进修率调整为0.001,迭代次数调整为6000,对模型进行优化。
low_latency_svdf 基于论文“运用秩约束拓扑结构实现深度神经网络压缩”中的拓扑结构。同样的,准确度相对于卷积网络来说偏低,但只需要运用75万个参数,最重要的是可以优化测试时的执行(当你实际运用你的应用时),最终只有75万次的浮点运算。
你可以在命令行中运用--model_architecture=low_latency_svdf来设定运用这个模型,接着更新训练的进修率和迭代次数,整体的代码如下:
需要注意的是虽然这个模型的迭代次数和前两个拓扑结构相比大了很多,但计算量的减少意味着在训练时最终所运用的时刻等于,最终的准确率可以达到85%。你可以通过调整SVDF层的这些参数,相对简单地调整这个拓扑结构的计算量和准确率。
秩 – 相似度的秩(这个值越高,准确度越好,但同时计算量会增大)
节点数量 – 和其他层类型相似,层中的节点数量(节点数越多,质量越好,同时计算量会越大)
关于运行时刻,思考到本层允许通过缓存一些内部神经网络的激活结局来进行优化,你需要保证当你暂停执行,或者在流传输玩法下执行模型时,需要保证运用的是同壹个步调(例如,'clip_stride_ms' 标志)。当你压缩图时,以及在流玩法下执行模型时(例如test_streaming_UNK acy.cc)。
如果你想尝试自定义模型,还有一些参数也可以进行自定义,比如可以从调整声谱图的创建参数开始。这个参数会调整模型输入的图像大致,在models.py文件中的创建代码会根据不同的维度对计算量和权重进行自适应。如果你的输入较小,那么模型会运用更小的运算量来进行处理,因此这是权衡准确度和减少延迟时刻的好方式。--window_stride_ms 参数可以控制每个频率的解析样本和前壹个之间的距离。如果增大这个值,那么在给定区间内的采样数会减少,输入的时刻轴也会缩小。--dct_coefficient_count参数控制用来统计频率的分类数量,因此如果减小这个值意味着从另壹个维度上缩小了输入。--window_size_ms参数不会影响输入的大致,然而它控制了计算每个样本频率的区域的宽度。如果你需要验证的声音很短,可以通过--clip_duration_ms参数来减少训练样本的时长,由于这样就是从时刻维度上减少了输入。然而你需要确保全部的训练数据在片段的初始部分中包含你所需要的正确音频。
针对你的难题,如果你脑海中有壹个完全不同的模型,你可以将其插入到models.py文件中,接着运用其他部分的脚本处理全部的预处理和训练机制。同时你需要在create_model中新增代码用来查询你的架构名称,接着调用模型的创建函数。这个函数中包含了声谱图的输入,以及一些其他模型信息,同时会创建TensorFlow的操作来读取数据、创建输出的预测给量,以及运用壹个占位符来控制神经元的丢失率。剩下的代码会将整个模型进行集成,执行输入计算,应用softmax函数以及损失函数来进行训练。
当你调整模型以及训练超参数时,普遍遇到的难题是由于数字精度的难题,有些数值并不可以进行缓慢变化。一般来说,你可以通过降低这些值的量级来处理,比如对于进修率和权重初始化函数。但如果这个难题还是持续存在,你可以运用--check_nans标志进行跟踪,寻找难题的根源。这个操作将在TensorFlow中的大多数常规操作之间插入检查操作,这样在遇到难题时,会停止训练经过并返回有用的错误信息。