# 语音识别: DeepSpeech2 *语音识别: DeepSpeech2*是一个采用[PaddlePaddle](https://github.com/PaddlePaddle/Paddle)平台的端到端自动语音识别(ASR)引擎的开源项目,具体原理参考这篇论文[Baidu's Deep Speech 2 paper](http://proceedings.mlr.press/v48/amodei16.pdf)。 我们的愿景是为语音识别在工业应用和学术研究上,提供易于使用、高效和可扩展的工具,包括训练,推理,测试模块,以及分布式的[PaddleCloud](https://github.com/PaddlePaddle/cloud)训练和demo部署。同时,我们还将发布一些预训练好的英语和普通话模型。 ## 目录 - [安装](#安装) - [开始](#开始) - [数据准备](#数据准备) - [训练模型](#训练模型) - [数据增强管道](#数据增强管道) - [推断和评价](#推断和评价) - [在Docker容器上运行](#在Docker容器上运行) - [分布式云训练](#分布式云训练) - [超参数调整](#超参数调整) - [训练汉语语言](#训练汉语语言) - [用自己的声音尝试现场演示](#用自己的声音尝试现场演示) - [发布模型](#发布模型) - [试验和基准](#试验和基准) - [问题和帮助](#问题和帮助) ## 安装 为了避免环境配置问题,强烈建议在[Docker容器上运行](#在Docker容器上运行),另外请按照下面的指南安装依赖项。 ### 前提 - 只支持Python 2.7 - PaddlePaddle最新版本(请参考[安装指南](https://github.com/PaddlePaddle/Paddle#installation)) ### 安装 - 请确保以下库或工具已安装完毕:`pkg-config`, `flac`, `ogg`, `vorbis`, `boost` 和 `swig`, 以上可以通过`apt-get`安装: ```bash sudo apt-get install -y pkg-config libflac-dev libogg-dev libvorbis-dev libboost-dev swig ``` - 为剩下的依赖项运行安装脚本 ```bash git clone https://github.com/PaddlePaddle/DeepSpeech.git cd DeepSpeech sh setup.sh ``` ## 开始 `./examples`里的一些shell脚本将帮助我们在一些公开数据集(比如:[LibriSpeech](http://www.openslr.org/12/), [Aishell](http://www.openslr.org/33)) 进行快速尝试,包括了数据准备,模型训练,案例推断和模型评价。阅读这些例子将帮助你理解如何应用你的数据集。 `./examples`目录中的一些脚本配置使用了8个GPU。如果你没有8个可用的GPU,请修改`CUDA_VISIBLE_DEVICES`和`--trainer_count`。如果你没有可用的GPU,请设置`--use_gpu`为False,这样程序会用CPU代替GPU。另外如果发生内存不足的问题,减小`--batch_size`即可。 让我们先看看[LibriSpeech dataset](http://www.openslr.org/12/)小样本集的例子。 - 转到目录 ```bash cd examples/tiny ``` 注意这仅仅是LibriSpeech一个小数据集的例子。如果你想尝试完整的数据集(可能需要花好几天来训练模型),请使用这个路径`examples/librispeech`。 - 准备数据 ```bash sh run_data.sh ``` 运行`run_data.sh`脚本将会下载数据集,产出manifests文件,收集一些归一化需要的统计信息并建立词表。当数据准备完成之后,下载完的数据(仅有LibriSpeech一部分)在`~/.cache/paddle/dataset/speech/libri`中;其对应的manifest文件,均值标准差和词表文件在`./data/tiny`中。在第一次执行的时候一定要执行这个脚本,在接下来所有的实验中我们都会用到这个数据集。 - 训练你自己的ASR模型 ```bash sh run_train.sh ``` `run_train.sh`将会启动训练任务,训练日志会打印到stdout,并且模型每个时期(epoch)的检查点都会保存到`./checkpoints/tiny`目录中。这些检查点可以用来恢复训练,推断,评价和部署。 - 用已有的模型进行案例推断 ```bash sh run_infer.sh ``` `run_infer.sh`将会利用训完的模型展现一些(默认10个)样本语音到文本的解码结果。由于当前模型只使用了LibriSpeech一部分数据集训练,因此性能可能不会太好。为了看到更好模型上的表现,你可以下载一个已训练好的模型(用完整的LibriSpeech训练了好几天)来做推断。 ```bash sh run_infer_golden.sh ``` - 评价一个已经存在的模型 ```bash sh run_test.sh ``` `run_test.sh`能够利用误字率(或字符错误率)来评价模型。类似的,你可以下载一个完全训练好的模型来测试它的性能: ```bash sh run_test_golden.sh ``` 更多细节会在接下来的章节中阐述。祝你在*语音识别: DeepSpeech2*ASR引擎学习中过得愉快! ## 数据准备 ### 生成Manifest *语音识别: DeepSpeech2*接受文本**manifest**文件作为数据接口。manifest文件包含了一系列语音数据,其中每一行代表一个json格式的音频元数据(比如文件路径,描述,时长)。具体格式如下: ``` {"audio_filepath": "/home/work/.cache/paddle/Libri/134686/1089-134686-0001.flac", "duration": 3.275, "text": "stuff it into you his belly counselled him"} {"audio_filepath": "/home/work/.cache/paddle/Libri/134686/1089-134686-0007.flac", "duration": 4.275, "text": "a cold lucid indifference reigned in his soul"} ``` 如果你要使用自定义数据,你只需要按照以上格式生成自己的manifest文件即可。训练,推断以及其他所有模块都能够根据manifest文件获取到音频数据,包括他们的元数据。 关于如何生成manifest文件,请参考`data/librispeech/librispeech.py`。该脚本将会下载LibriSpeech数据集并生成manifest文件。 ### 计算均值和标准差用于归一化 为了对音频特征进行z-score归一化(零均值,单位标准差),我们必须预估一些训练样本特征的均值和标准差: ```bash python tools/compute_mean_std.py \ --num_samples 2000 \ --specgram_type linear \ --manifest_paths data/librispeech/manifest.train \ --output_path data/librispeech/mean_std.npz ``` 以上这段代码会计算在`data/librispeech/manifest.train`路径中,2000个随机采样音频剪辑的功率谱特征均值和标准差,并将结果保存在`data/librispeech/mean_std.npz`中,方便以后使用。 ### 建立词表 转换录音为索引用于训练,解码,再将一系列索引转换为文本等操作需要一个可能会出现字符集合的词表。`tools/build_vocab.py`脚本将生成这种基于字符的词表。 ```bash python tools/build_vocab.py \ --count_threshold 0 \ --vocab_path data/librispeech/eng_vocab.txt \ --manifest_paths data/librispeech/manifest.train ``` 他将`data/librispeech/manifest.train`目录中的所有录音文本写入词表文件`data/librispeeech/eng_vocab.txt`,并且没有词汇截断(`--count_threshold 0`)。 ### 更多帮助 获得更多帮助: ```bash python data/librispeech/librispeech.py --help python tools/compute_mean_std.py --help python tools/build_vocab.py --help ``` ## 训练模型 `train.py`是训练模块的主要调用者。使用示例如下。 - 开始使用8片GPU训练: ``` CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 python train.py --trainer_count 8 ``` - 开始使用16片GPU训练: ``` python train.py --use_gpu False --trainer_count 16 ``` - 从检查点恢复训练: ``` CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ python train.py \ --init_model_path CHECKPOINT_PATH_TO_RESUME_FROM ``` 获得更多帮助: ```bash python train.py --help ``` 或参考 `example/librispeech/run_train.sh`. ## 数据增强管道 数据增强是用来提升深度学习性能的非常有效的技术。我们通过在原始音频中添加小随机扰动(标签不变转换)获得新音频来增强我们的语音数据。你不必自己合成,因为数据增强已经嵌入到数据提供者中,能在训练模型时每个epoch中随机的合成音频。 目前提供六个可选的增强组件供选择,配置并插入处理流水线。 - 音量扰动 - 速度扰动 - 移动扰动 - 在线贝叶斯归一化 - 噪声干扰(需要背景噪音的音频文件) - 脉冲响应(需要脉冲音频文件) 为了让训练模块知道需要哪些增强组件以及它们的处理顺序,我们需要事先准备一个[JSON](http://www.json.org/)格式的*扩展配置文件*。例如: ``` [{ "type": "speed", "params": {"min_speed_rate": 0.95, "max_speed_rate": 1.05}, "prob": 0.6 }, { "type": "shift", "params": {"min_shift_ms": -5, "max_shift_ms": 5}, "prob": 0.8 }] ``` 当`trainer.py`的`--augment_conf_file`参数被设置为上述示例配置文件的路径时,每个epoch中的每个音频片段都将被处理。首先,均匀随机采样速率会有60%的概率在0.95和1.05之间对音频片段进行速度扰动。然后,音频片段有80%的概率在时间上被挪移,挪移偏差值是-5毫秒和5毫秒之间的随机采样。最后,这个新合成的音频片段将被传送给特征提取器,以用于接下来的训练。 有关其他配置实例,请参考`conf/augmenatation.config.example`. 使用数据增强技术时要小心,由于扩大了训练和测试集的差异,不恰当的增强会对训练模型不利。 ## 推断和评价 ### 准备语言模型 提升解码器的性能需要准备语言模型。我们准备了两种语言模型(有损压缩)供用户下载和尝试。一个是英语模型,另一个是普通话模型。用户可以执行以下命令来下载已经训练好的语言模型: ```bash cd models/lm sh download_lm_en.sh sh download_lm_ch.sh ``` 如果你想训练自己更好的语言模型,请参考[KenLM](https://github.com/kpu/kenlm)获取教程。在这里,我们提供一些技巧来展示我们如何准备我们的英语和普通话模型。开始训练的时候,你可以参考这些技巧。 #### 英语语言模型 英语语料库来自[Common Crawl Repository](http://commoncrawl.org),您可以从[statmt](http://data.statmt.org/ngrams/deduped_en)下载它。我们使用en.00部分来训练我们的英语语言模型。训练前有一些预处理步骤如下: * 不在\[A-Za-z0-9\s'\](\s表示空白字符)中的字符将被删除,阿拉伯数字被转换为英文数字,比如“1000”转换为one thousand。 * 重复的空白字符被压缩为一个,并且开始的空白字符将被删除。请注意,所有的录音都是小写字母,因此所有字符都转换为小写字母。 * 选择前40万个最常用的单词来建立词表,其余部分将被替换为“UNKNOWNWORD”。 现在预处理完成了,我们得到一个干净的语料库来训练语言模型。我们发布的语言模型版本使用了参数“-o 5 --prune 0 1 1 1 1”来训练。“-o 5”表示语言模型的最大order为5。“--prune 0 1 1 1 1”表示每个order的计数阈值,更具体地说,它将第2个以及更高的order修剪为单个。为了节省磁盘存储空间,我们将使用参数“-a 22 -q 8 -b 8”将arpa文件转换为“trie”二进制文件。“-a”表示在“trie”中用于切分的指针的最高位数。“-q -b”是概率和退避的量化参数。 #### 普通话语言模型 与英语语言模型不同的是,普通话语言模型是基于字符的,其中每一位都是中文汉字。我们使用内部语料库来训练发布的汉语语言模型。该语料库包含数十亿汉字。预处理阶段与英语语言模型差别很小,主要步骤包括: * 删除开始和结尾的空白字符。 * 删除英文标点和中文标点。 * 在两个字符之间插入空白字符。 请注意,发布的语言模型只包含中文简体字。预处理完成后,我们开始训练语言模型。这个小的语言模型训练关键参数是“-o 5 --prune 0 1 2 4 4”,“-o 5”是针对大语言模型。请参考上面的部分了解每个参数的含义。我们还使用默认设置将arpa文件转换为二进制文件。 ### 语音到文本推断 推断模块调用者为`infer.py`,可以用来推断,解码,以及给一些给定音频剪辑进行可视化语音到文本的结果。这有助于对ASR模型的性能进行直观和定性的评估。 - GPU版本的推断: ```bash CUDA_VISIBLE_DEVICES=0 python infer.py --trainer_count 1 ``` - CPU版本的推断: ```bash python infer.py --use_gpu False --trainer_count 12 ``` 我们提供两种类型的CTC解码器:*CTC贪心解码器*和*CTC波束搜索解码器*。*CTC贪心解码器*是简单的最佳路径解码算法的实现,在每个时间步选择最可能的字符,因此是贪心的并且是局部最优的。[*CTC波束搜索解码器*](https://arxiv.org/abs/1408.2873)另外使用了启发式广度优先图搜索以达到近似全局最优; 它也需要预先训练的KenLM语言模型以获得更好的评分和排名。解码器类型可以用参数`--decoding_method`设置。 获得更多帮助: ``` python infer.py --help ``` 或参考`example/librispeech/run_infer.sh`. ### 评估模型 要定量评估模型的性能,请运行: - 带GPU版本评估 ```bash CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 python test.py --trainer_count 8 ``` - CPU版本评估 ```bash python test.py --use_gpu False --trainer_count 12 ``` 错误率(默认:误字率;可以用--error_rate_type设置)将被打印出来。 获得更多帮助: ```bash python test.py --help ``` 或参考`example/librispeech/run_test.sh`. ## 超参数调整 [*CTC波束搜索解码器*](https://arxiv.org/abs/1408.2873)的超参数$\alpha$(语言模型权重)和$\beta$(单词插入权重)对解码器的性能有非常显著的影响。当声学模型更新时,最好在验证集上重新调整它们。 `tools/tune.py`会进行2维网格查找超参数$\alpha$和$\beta$。您必须提供$\alpha$和$\beta$的范围,以及尝试的次数。 - 带GPU版的调整: ```bash CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ python tools/tune.py \ --trainer_count 8 \ --alpha_from 1.0 \ --alpha_to 3.2 \ --num_alphas 45 \ --beta_from 0.1 \ --beta_to 0.45 \ --num_betas 8 ``` - CPU版的调整: ```bash python tools/tune.py --use_gpu False ``` 网格搜索将会在超参数空间的每个点处打印出WER(误字率)或者CER(字符错误率),并且可选择绘出误差曲面。合适的超参数范围应包括WER/CER误差表面的全局最小值,如下图所示。
调整LibriSpeech的dev-clean集合的误差曲面示例