如何训练一个简单的语音识别网络模型---基于TensorFlow

这篇文章是翻译自Google的教程;还有一部分没完成,但今天上去发现登录不了,只好先发这部分上来。
欢迎有兴趣学习的朋友,与我交流。微信:18221205301

如何训练一个简单的语音识别网络模型

本教程旨在说明如何建立一个简单的包含10个词条的语音识别网络。需要提醒的是,真实的语音识别系统要更加复杂,但如同MNIST之于图像,本网络模型可以让大家了解相关技术实现的过程。当你完成本教程之后,可以获得一个模型,它可以识别一个1秒语音clip比如“静音”、 “yes”, “no”, “up”, “down”, “left”, “right”, “on”, “off”, “stop”, or “go”. 等未知词条。你还可以让这个模型在一个安卓应用里运行起来。

准备


首先要确认已经安装好TensorFlow。
鉴于脚本需要下载超过1GB的训练数据,你要保证处于满格的WIFI环境(土豪4G流量请随意,不过土豪有来学程序的吗?),计算机清理出足够的空间。整个训练过程需要花费几个小时,所以最好有个妹子陪着,聊聊人类被AI统治之后的爱情。

训练


开始训练,在TensorFlow的source tree下运行:
python tensorflow/examples/speech_commands/train.py
脚本首先下载 Speech Commands dataset由65000个WAVE语音音频文件组成,包括30个词条。数据是由Google采集并发布的,受 CC BY license保护,你也可以帮助补充这个数据集,通过 contributing five minutes of your own voice. 目录超过1GB,下载需要花点时间,你能够看到过程提醒,完成之后,以后就不用再执行这个步骤。

下载完成,你可以看到如下的信息提示:

I0730 16:53:44.766740 55030 train.py:176] Training from step: 1
I0730 16:53:47.289078 55030 train.py:217] Step #1: rate 0.001000, accuracy 7.0%, cross entropy 2.611571

表示初始化过程完成,训练循环开始。你可以看到每一步训练的输出信息。在此说明:
Step #1 表明处于训练循环的第一步。在本案例中,总共有18,000步,所以你可以通过Step的数字了解到离完成还有多远。
rate 0.001000表示学习率,用来控制网络模型权重的更新速度。开始的时候学习率是一个比较高的值(0.01),在后面的训练周期大约下降10倍,到0.0001。
accuracy 7.0%表示每一步训练时预测的准确率。这个值会有较大的浮动,但整体上在训练的过程中是不断提高。模型输出为数字矩阵,其中一列为label标签,每个数字表示对应各个分类预测得出的似然率。预测结果的label标签选取得分最高的那一项。得分总是在0~1之间,越高表示结果越可信。
cross entropy 2.611571用来指导训练过程的损失函数的结果。This is a score that’s obtained by comparing the vector of scores from the current training run to the correct labels, and this should trend downwards during training.
在100步之后,可以看到如下的提示行:
I0730 16:54:41.813438 55030 train.py:252] Saving to "/tmp/speech_commands_train/conv.ckpt-100"
表示保存当前训练的权重到一个checkpoint文件中。如果你的训练脚本被中断,你可以看到最后保存的checkpoint,通过
--start_checkpoint=/tmp/speech_commands_train/conv.ckpt-100命令行参数,可以从当前点重新启动脚本。

安卓应用中运行模型


想要了解模型是如何在一个真实的应用中运行,最快捷的办法是去下载the prebuilt Android demo applications并在手机上安装。你可以看到“TF Speech”出现在应用列表,打开它,可以看到模型中训练过的词条列表,从“yes”和“no”开始。授权麦克使用权限之后,你可以尝试读出词条,UI中会对应高亮该词,说明模型进行了识别。

用户也可以构建自己的应用,开源代码在available as part of the TensorFlow repository on github. 默认情况下,从tensorflow.org下载一个未训练的模型a pretrained model from tensorflow.org,,然后可以轻松地替换成你自己训练好的模型,这么做之前,要确认 the main SpeechActivity Java source file中 SAMPLE_RATE 和 SAMPLE_DURATION此类常量与你训练时所做改动相匹配。还提供一个类似C++的Java版本的模型如果之前调整了参数,你也可以在SpeechActivity 中更新以得到同样的测试结果。

拷贝标签文本文件到固定的graph中,Demo应用自动更新UI列表。这样可以轻松的尝试不同的模型而无需更改代码。若改变路径,你需要更新LABEL_FILENAME 和 MODEL_FILENAME 指定你添加的文件。

模型如何工作


本教程中的架构基于论文Convolutional Neural Networks for Small-footprint Keyword Spotting不代表当前最新最高的技术水准,好处在于相对简单,训练速度快,易于理解。有很多方法构建一个语音识别的神经网络,比如recurrent networksdilated (atrous) convolutions
本教程基于卷积神经网络,有过图像识别研究的人对此会非常熟悉。然而语音数据本质上是连续的一维信号,而不是2维空间的问题,采用卷积神经网络看起来不合情理。

解决这个问题,我们定义一个时间窗,将时间窗内的语音信号转换为一个图像。具体办法是把若干输入音频采样组合成几秒长度的短片段,计算带宽范围内的强度和频率。每个片段的频率、强度被看做数字向量,这些向量再被组织成2维矩阵。矩阵的值也就是频谱,可以被看做是单色图像。要了解音频采样如何被组织成图片,可以运行 wav_to_spectrogram 工具:
bazel run tensorflow/examples/wav_to_spectrogram:wav_to_spectrogram -- \
--input_wav=/tmp/speech_dataset/happy/ab00c4b2_nohash_0.wav \
--output_png=/tmp/spectrogram.png

打开/tmp/spectrogram.png 可以看到类似下面的图片:
enter image description here
鉴于TensorFlow的存储方式,图中的时间轴从上到下,频率从左到右,和通常的频谱图时间从左到右不同。从图中可以看到若干不连续的部分,这是由于第一个音节“Ha”和“ppy”分开的原因。

人类的耳朵对某些频率的敏感度远大于其它,传统的做法是在语音识别中做更深入的处理,将表述转为一组 Mel-Frequency Cepstral Coefficients或短MFCC。这也是一个两位单通道的表述,所以也可以被看做是一个图片。如果你处理的是自然音而不是语音,事实上你可以跳过这一步直接操作频谱。

得到的图像送入多层卷积神经网络处理,最后是一个全连接层紧跟一个softmax函数。你可以在tensorflow/examples/speech_commands/models.py.看到这部分的描述。

Streaming Accuracy


绝大多数音频识别应用需要处理的是连续音频流,而不是独立的clips。这种情况下典型的处理是apply it repeatedly at different offsets in time and average the results over a short window to produce a smoothed prediction.在不同的时间偏移上重复操作,对结果再一个小的窗口上取平均,这样得到一个平滑的预测。如果把输入看成一幅图片,那么它是在时间轴上连续滚动的。我们要识别的词条可能在任意时间点开始,所以必须做一系列的采样,尽可能在加入到模型的时间窗口里捕捉到所有发音。如果采样速度足够高,就可以有很大的可能性在多个窗口中捕捉到这个词条,这样对结果再做平均就可以很好的提高预测的可信度。

用一个例子来说明如何在连续流数据中应用模型,可以参考test_streaming_accuracy.cc它使用了RecognizeCommands类来运行在一个长格式输入音频中如何分割词条并且针对标签和时间的ground truth 表来比较这些预测和。his uses the RecognizeCommands class to run through a long-form input audio, try to spot words, and compare those predictions against a ground truth list of labels and times. 成为将模型应用于音频流信号的很好的例子。

你将需要一个长音频信号去测试它,这个长音频信号针对所说每个词条都带标签。如果不想自己去录,可以用generate_streaming_test_wav工具来合成测试数据。默认情况下,将产生一个10分钟的wav文件(每个词条大约3秒),以及一个包含每个词条ground truth的文本文件。这些词从当前数据集的测试部分取出并混合背景噪音。用下列的命令运行:
bazel run tensorflow/examples/speech_commands:generate_streaming_test_wav
将会把.wav文件保存到/tmp/speech_commands_train/streaming_test.wav以及一个列出标签的文本文件保存到/tmp/speech_commands_train/streaming_test_labels.txt.可用下列命令运行测试准确率:
bazel run tensorflow/examples/speech_commands:test_streaming_accuracy -- \
--graph=/tmp/my_frozen_graph.pb \
--labels=/tmp/speech_commands_train/conv_labels.txt \
--wav=/tmp/speech_commands_train/streaming_test.wav \
--ground_truth=/tmp/speech_commands_train/streaming_test_labels.txt \
--verbose

输出的信息内容包括:正确匹配的词条数目、给出错误标签的数目以及多少次模型触发了但实际没有词条被读出。有很多参数可以控制信号平均工作,包括–average_window_ms :用来设置平均结果的时间长度,–sample_stride_ms表示模型应用之间的时间,–suppression_ms 在初始化1出现之后停止一段时间检测随后词条 –detection_threshold, 控制如何提高判断为稳定结果的平均分值的阈值
你将会看到流准确率输出3个数字,而不仅是训练中的一个矩阵。这是因为不同的应用有不同的需求,其中部分只要正确的词被找到,能够允许一些的错误结果(high recall),而其他一部分要保证对所有词条只要预测了就尽可能正确,尽管有些词条没有检测到(high precision)。工具给出的数值提供给你一个思路,如何执行应用,且你如何调整信号平均参数以达到你想要的性能。为了理解什么是你应用的合适参数,可以通过产生一个ROC curve来帮助你理解如何权衡。

识别命令


流准确率工具采用一个small C++类中包含的简单解码器RecognizeCommands,这个类实时提供TensorFlow模型运行的输出,
它平均信号,在有足够证据表明发现一个被识别的词条时提供标签信息。这个实现非常小,只需要跟踪最新的几个预测并且取平均,所以很容易和其他平台以及语言接口对接。举个例子,很多时候在用java在安卓上或者Python在Raspberry上开发一些彼此类似的工作。只要他们的实现的部分使用同样的逻辑,你就可以调节参数用控制流测试工具控制均值,然后转换到你的应用以得到相似的结果。

高级训练


默认状态下,训练脚本是为在一个相对较小的文件中得到完整的结果。但是你仍然可以根据自己需求定制化修改结果。

制作训练数据

默认情况下,脚本从 Speech Commands dataset下载数据,但是也可以采用你自己的训练数据。为了训练你自己的数据,要确认至少为每个声音有几百条录音,并且根据类别保存到对应目录。举个例子,如果你试着识别狗的叫声和猫的叫声,你需要建一个名为animal_sounds的根目录,下面再建两个名为barkmiaow的子目录。你需要把对应的音频文件放到相应的目录中去。

为了将你的脚本指向到新的音频文件,你需要设置--data_url=来禁止再下载Speech Commands dataset,而到--data_dir=/your/data/folder/去寻找你刚建立的文件。

文件需要是16bit 小端PCM编码的WAVE格式。采样速率默认为16000,但是只要你所有的音频是保持在同样的速率(脚本不支持重采样),你可以通过--sample_rate来改变这个参数。每个clips要保持在大约一致的时间长度,默认为1秒,也可以通过--clip_duration_ms来设置。如果你的clips在开始阶段有大量的静音部分,你可以通过词条规整工具来标准化它们。

有一个必须要注意的问题是,同样的声音在你的数据集中可能有重复的副本,如果它们被使用到训练、验证、以及测试数据集中,将会产生误导。举个例子,在 Speech Commands set中有多次重复同一个词。每个副本之间非常接近,所以训练会导致过拟合以及记性效应,当它在测试集中看到一个非常接近的副本会表现的好到不切实际。为了避免这个风险, Speech Commands尝试去确保所有的同一人对同一词条读出的clips放置到同一个部分。Clips根据它们的文件名被指定到训练集、验证集或者测试集,这样即使添加新clips时也可以保证分配是稳定的,并且避免采样混合到其他数据集中。确保某一制定说话者的所有词条都在同一个集里, the hashing function确定划分归属的时候,在’nohash‘之后忽略文件名中的任何内容。这意味着如果你的文件名类似于pete_nohash_0.wav and pete_nohash_1.wav,它们就会保证被划分到同一数据集。

未知类别

应用可能会听到不属于你训练集的声音,你希望模型能够标明这是不可识别的噪音。为了帮助网络模型学习如何忽略此类声音,你需要提供一些不属于既定类别的clips。这就要建几个类似 quack, oink, and moo 的子目录并添加用户可能遇到的其它动物的噪音。脚本中--wanted_words参数确定你所关注的类别,训练中所有其它的子目录将被添加到一个__unkown__的类别。 Speech Commands 数据集在未知类别里有20个词条,包括数字0到9以及随机名字如“Shella”

默认情况下,有10%的训练样本是从未知类别里取出的,但你也可以通过--unknown_percentage标志来设置。增加这个值将使得模型将未知词误判的可能性降低,但是如果这个值太大的话,可能就会让模型认为干脆将所有词判成未知是最安全的。

背景噪声

在实际应用中,对音频的识别总是会有其它无关声音的干扰。为了建立模型对此类干扰的鲁棒性,训练时,需要所录制的音频也要有类似噪声背景的特性。Speech Commands数据集的文件,并不是在某个录音室,而是用不同的设备在让使用者在不同环境中录制的。所以这使得训练具有一定现实性。要增加更多现实性,可以在训练的输入里混入环境声音的随机片段。在Speech Commands数据集中有一个特殊目录名为background_noise,这里面就包括了分钟量级的白噪音以及机器声和每天的日常噪声。

训练过程中抽取这些文件中的小片段以较低音量混入clips。音量也是随机设定,由--background_volume设定。这个参数是一个比率,0代表静音,1是全音量。并不是所有clips都有背景加入,所以--background_frequency控制混入的比例。

你的应用场合背景噪声可能与默认情况不同,所以可以将你自己的音频clips放到_background_noise_这个目录中去。相对于你主数据集,要保证采样速率一致而时间长度要大大超过。这样可以从中选择任意随机部分。

静音
  • 5
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值