From 8e5243dab593bee6c04edcc9d419f6b78079665b Mon Sep 17 00:00:00 2001 From: lfchener Date: Fri, 18 Oct 2019 11:46:00 +0000 Subject: [PATCH] unify api to 1.6 version and fix some problems --- README.md | 4 +- README_cn.md | 94 +++++++++++++++---------------- data_utils/data.py | 2 +- deploy/demo_server.py | 2 +- examples/aishell/run_train.sh | 2 +- examples/librispeech/run_train.sh | 2 +- examples/tiny/run_train.sh | 2 +- infer.py | 9 ++- model_utils/model.py | 76 +++++++++++++------------ model_utils/model_check.py | 49 ++++++++++++++++ model_utils/network.py | 28 ++++----- test.py | 9 ++- tools/tune.py | 2 +- train.py | 13 ++++- 14 files changed, 184 insertions(+), 110 deletions(-) create mode 100644 model_utils/model_check.py diff --git a/README.md b/README.md index d12f2521f..806070084 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ To avoid the trouble of environment setup, [running in Docker container](#runnin ### Prerequisites - Python 2.7 only supported -- PaddlePaddle the latest version (please refer to the [Installation Guide](https://www.paddlepaddle.org.cn/documentation/docs/en/1.5/beginners_guide/install/index_en.html)) +- PaddlePaddle 1.6 version (Coming soon ...) ### Setup - Make sure these libraries or tools installed: `pkg-config`, `flac`, `ogg`, `vorbis`, `boost` and `swig`, e.g. installing them via `apt-get`: @@ -183,7 +183,7 @@ python tools/build_vocab.py --help ``` CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ python train.py \ - --init_from_pretrain_model CHECKPOINT_PATH_TO_RESUME_FROM + --init_from_pretrained_model CHECKPOINT_PATH_TO_RESUME_FROM ``` For more help on arguments: diff --git a/README_cn.md b/README_cn.md index dfdc15d3d..90ae6f48c 100644 --- a/README_cn.md +++ b/README_cn.md @@ -1,16 +1,16 @@ # 语音识别: DeepSpeech2 -*语音识别: DeepSpeech2*是一个采用[PaddlePaddle](https://github.com/PaddlePaddle/Paddle)平台的端到端自动语音识别(ASR)引擎的开源项目,具体原理参考这篇论文[Baidu's Deep Speech 2 paper](http://proceedings.mlr.press/v48/amodei16.pdf)。 -我们的愿景是为语音识别在工业应用和学术研究上,提供易于使用、高效和可扩展的工具,包括训练,推理,测试模块,以及demo部署。同时,我们还将发布一些预训练好的英语和普通话模型。 +*DeepSpeech2*是一个采用[PaddlePaddle](https://github.com/PaddlePaddle/Paddle)平台的端到端自动语音识别(ASR)引擎的开源项目,具体原理参考这篇论文[Baidu's Deep Speech 2 paper](http://proceedings.mlr.press/v48/amodei16.pdf)。 +我们的愿景是为语音识别在工业应用和学术研究上,提供易于使用、高效和可扩展的工具,包括训练,推理,测试模块,以及 demo 部署。同时,我们还将发布一些预训练好的英语和普通话模型。 ## 目录 - [安装](#安装) - [开始](#开始) - [数据准备](#数据准备) - [训练模型](#训练模型) -- [数据增强管道](#数据增强管道) +- [数据增强流水线](#数据增强流水线) - [推断和评价](#推断和评价) -- [在Docker容器上运行](#在Docker容器上运行) +- [在 Docker 容器上运行](#在Docker容器上运行) - [超参数调整](#超参数调整) - [训练汉语语言](#训练汉语语言) - [用自己的声音尝试现场演示](#用自己的声音尝试现场演示) @@ -23,7 +23,7 @@ ### 前提 - 只支持Python 2.7 -- PaddlePaddle最新版本(请参考[安装指南](https://www.paddlepaddle.org.cn/start)) +- PaddlePaddle 1.6 版本(即将发布) ### 安装 - 请确保以下库或工具已安装完毕:`pkg-config`, `flac`, `ogg`, `vorbis`, `boost` 和 `swig`, 如可以通过`apt-get`安装: @@ -55,40 +55,40 @@ sh setup.sh ## 开始 -`./examples`里的一些shell脚本将帮助我们在一些公开数据集(比如:[LibriSpeech](http://www.openslr.org/12/), [Aishell](http://www.openslr.org/33)) 进行快速尝试,包括了数据准备,模型训练,案例推断和模型评价。阅读这些例子将帮助你理解如何使用你的数据集训练模型。 +`./examples`里的一些 shell 脚本将帮助我们在一些公开数据集(比如:[LibriSpeech](http://www.openslr.org/12/), [Aishell](http://www.openslr.org/33)) 进行快速尝试,包括了数据准备,模型训练,案例推断和模型评价。阅读这些例子将帮助你理解如何使用你的数据集训练模型。 -`./examples`目录中的一些脚本配置使用了8个GPU。如果你没有8个可用的GPU,请修改`CUDA_VISIBLE_DEVICES`。如果你没有可用的GPU,请设置`--use_gpu`为False,这样程序会用CPU代替GPU。另外如果发生内存不足的问题,减小`--batch_size`即可。 +`./examples`目录中的一些脚本配置使用了 8 个 GPU。如果你没有 8 个可用的 GPU,请修改环境变量`CUDA_VISIBLE_DEVICES`。如果你没有可用的 GPU,请设置`--use_gpu`为 False,这样程序会用 CPU 代替 GPU。另外如果发生内存不足的问题,减小`--batch_size`即可。 让我们先看看[LibriSpeech dataset](http://www.openslr.org/12/)小样本集的例子。 -- 进到目录 +- 进入目录 ```bash cd examples/tiny ``` - 注意这仅仅是LibriSpeech一个小数据集的例子。如果你想尝试完整的数据集(可能需要花好几天来训练模型),请使用这个路径`examples/librispeech`。 + 注意这仅仅是 LibriSpeech 一个小数据集的例子。如果你想尝试完整的数据集(可能需要花好几天来训练模型),请使用这个路径`examples/librispeech`。 - 准备数据 ```bash sh run_data.sh ``` - 运行`run_data.sh`脚本将会下载数据集,产出manifests文件,收集一些归一化需要的统计信息并建立词表。当数据准备完成之后,下载完的数据(仅有LibriSpeech一部分)在`dataset/librispeech`中;其对应的manifest文件,均值标准差和词表文件在`./data/tiny`中。在第一次执行的时候一定要执行这个脚本,在接下来所有的实验中我们都会用到这个数据集。 -- 训练你自己的ASR模型 + 运行`run_data.sh`脚本将会下载数据集,产出 manifests 文件,收集一些归一化需要的统计信息并建立词表。当数据准备完成之后,下载完的数据(仅有 LibriSpeech 一部分)在`dataset/librispeech`中;其对应的 manifest 文件,均值标准差和词表文件在`./data/tiny`中。在第一次执行的时候一定要执行这个脚本,在接下来所有的实验中我们都会用到这个数据集。 +- 训练你自己的 ASR 模型 ```bash sh run_train.sh ``` - `run_train.sh`将会启动训练任务,训练日志会打印到终端,并且模型每个epoch的checkpoint都会保存到`./checkpoints/tiny`目录中。这些checkpoint可以用来恢复训练,推断,评价和部署。 + `run_train.sh`将会启动训练任务,训练日志会打印到终端,并且模型每个 epoch 的 checkpoint 都会保存到`./checkpoints/tiny`目录中。这些 checkpoint 可以用来恢复训练,推断,评价和部署。 - 用已有的模型进行案例推断 ```bash sh run_infer.sh ``` - `run_infer.sh`将会利用训练好的模型展现一些(默认10个)样本语音到文本的解码结果。由于当前模型只使用了LibriSpeech一部分数据集训练,因此性能可能不会太好。为了看到更好模型上的表现,你可以下载一个已训练好的模型(用完整的LibriSpeech训练了好几天)来做推断。 + `run_infer.sh`将会利用训练好的模型展现一些(默认 10 个)样本语音到文本的解码结果。由于当前模型只使用了 LibriSpeech 一部分数据集训练,因此性能可能不会太好。为了看到更好模型上的表现,你可以下载一个已训练好的模型(用完整的 LibriSpeech 训练了好几天)来做推断。 ```bash sh run_infer_golden.sh @@ -105,27 +105,27 @@ sh setup.sh sh run_test_golden.sh ``` -更多细节会在接下来的章节中阐述。祝你在*语音识别: DeepSpeech2*ASR引擎学习中过得愉快! +更多细节会在接下来的章节中阐述。祝你在*DeepSpeech2*ASR引擎学习中过得愉快! ## 数据准备 ### 生成Manifest -*语音识别: DeepSpeech2*接受文本**manifest**文件作为数据接口。manifest文件包含了一系列语音数据,其中每一行代表一个[JSON](http://www.json.org/)格式的音频元数据(比如文件路径,描述,时长)。具体格式如下: +*DeepSpeech2*接受文本**manifest**文件作为数据接口。manifest 文件包含了一系列语音数据,其中每一行代表一个[JSON](http://www.json.org/)格式的音频元数据(比如文件路径,描述,时长)。具体格式如下: ``` {"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 文件即可。给定 manifest 文件,训练、推断以及其它所有模块都能够访问到音频数据以及对应的时长和标签数据。 -关于如何生成manifest文件,请参考`data/librispeech/librispeech.py`。该脚本将会下载LibriSpeech数据集并生成manifest文件。 +关于如何生成 manifest 文件,请参考`data/librispeech/librispeech.py`。该脚本将会下载 LibriSpeech 数据集并生成 manifest 文件。 ### 计算均值和标准差用于归一化 -为了对音频特征进行z-score归一化(零均值,单位标准差),我们必须预估训练样本特征的均值和标准差: +为了对音频特征进行 z-score 归一化(零均值,单位标准差),我们必须预估训练样本特征的均值和标准差: ```bash python tools/compute_mean_std.py \ @@ -135,7 +135,7 @@ python tools/compute_mean_std.py \ --output_path data/librispeech/mean_std.npz ``` -以上这段代码会计算在`data/librispeech/manifest.train`路径中,2000个随机采样的语音频谱特征的均值和标准差,并将结果保存在`data/librispeech/mean_std.npz`中,方便以后使用。 +以上这段代码会计算在`data/librispeech/manifest.train`路径中,2000 个随机采样的语音频谱特征的均值和标准差,并将结果保存在`data/librispeech/mean_std.npz`中,方便以后使用。 ### 建立词表 @@ -164,13 +164,13 @@ python tools/build_vocab.py --help `train.py`是训练模块的主要调用者。使用示例如下。 -- 开始使用8片GPU训练: +- 开始使用 8 片 GPU 训练: ``` CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 python train.py ``` -- 开始使用CPU训练: +- 开始使用 CPU 训练: ``` python train.py --use_gpu False @@ -181,7 +181,7 @@ python tools/build_vocab.py --help ``` CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ python train.py \ - --init_from_pretrain_model CHECKPOINT_PATH_TO_RESUME_FROM + --init_from_pretrained_model CHECKPOINT_PATH_TO_RESUME_FROM ``` 获得更多帮助: @@ -192,7 +192,7 @@ python train.py --help 或参考 `example/librispeech/run_train.sh`. -## 数据增强管道 +## 数据增强流水线 数据增强是用来提升深度学习性能的非常有效的技术。我们通过在原始音频中添加小的随机扰动(标签不变转换)获得新音频来增强我们的语音数据。你不必自己合成,因为数据增强已经嵌入到数据生成器中并且能够即时完成,在训练模型的每个epoch中随机合成音频。 @@ -222,7 +222,7 @@ python train.py --help }] ``` -当`trainer.py`的`--augment_conf_file`参数被设置为上述示例配置文件的路径时,每个epoch中的每个音频片段都将被处理。首先,均匀随机采样速率会有60%的概率在0.95和1.05之间对音频片段进行速度扰动。然后,音频片段有80%的概率在时间上被挪移,挪移偏差值是-5毫秒和5毫秒之间的随机采样。最后,这个新合成的音频片段将被传送给特征提取器,以用于接下来的训练。 +当`trainer.py`的`--augment_conf_file`参数被设置为上述示例配置文件的路径时,每个 epoch 中的每个音频片段都将被处理。首先,均匀随机采样速率会有60%的概率在 0.95 和 1.05 之间对音频片段进行速度扰动。然后,音频片段有 80% 的概率在时间上被挪移,挪移偏差值是 -5 毫秒和 5 毫秒之间的随机采样。最后,这个新合成的音频片段将被传送给特征提取器,以用于接下来的训练。 有关其他配置实例,请参考`conf/augmenatation.config.example`. @@ -247,11 +247,11 @@ bash download_lm_ch.sh 英语语料库来自[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。 + * 不在\['A-Za-z0-9\s'\](\s表示空白字符)中的字符将被删除,阿拉伯数字被转换为英文数字,比如“1000”转换为 one thousand。 * 重复的空白字符被压缩为一个,并且开始的空白字符将被删除。请注意,所有的录音都是小写字母,因此所有字符都转换为小写字母。 - * 选择前40万个最常用的单词来建立词表,其余部分将被替换为“UNKNOWNWORD”。 + * 选择前 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 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”是概率和退避的量化参数。 #### 普通话语言模型 @@ -261,25 +261,25 @@ bash download_lm_ch.sh * 删除英文标点和中文标点。 * 在两个字符之间插入空白字符。 -请注意,发布的语言模型只包含中文简体字。预处理完成后,我们开始训练语言模型。这个小的语言模型训练关键参数是“-o 5 --prune 0 1 2 4 4”,“-o 5”是针对大语言模型。请参考上面的部分了解每个参数的含义。我们还使用默认设置将arpa文件转换为二进制文件。 +请注意,发布的语言模型只包含中文简体字。预处理完成后,我们开始训练语言模型。这个小的语言模型训练关键参数是“-o 5 --prune 0 1 2 4 4”,“-o 5”是针对大语言模型。请参考上面的部分了解每个参数的含义。我们还使用默认设置将 arpa 文件转换为二进制文件。 ### 语音到文本推断 推断模块使用`infer.py`进行调用,可以用来推断,解码,以及输出一些给定音频片段可视化到文本的结果。这有助于对ASR模型的性能进行直观和定性的评估。 -- GPU版本的推断: +- GPU 版本的推断: ```bash CUDA_VISIBLE_DEVICES=0 python infer.py ``` -- CPU版本的推断: +- CPU 版本的推断: ```bash python infer.py --use_gpu False ``` -我们提供两种类型的CTC解码器:*CTC贪心解码器*和*CTC波束搜索解码器*。*CTC贪心解码器*是简单的最佳路径解码算法的实现,在每个时间步选择最可能的字符,因此是贪心的并且是局部最优的。[*CTC波束搜索解码器*](https://arxiv.org/abs/1408.2873)另外使用了启发式广度优先图搜索以达到近似全局最优; 它也需要预先训练的KenLM语言模型以获得更好的评分和排名。解码器类型可以用参数`--decoding_method`设置。 +我们提供两种类型的 CTC 解码器:*CTC贪心解码器*和*CTC波束搜索解码器*。*CTC贪心解码器*是简单的最佳路径解码算法的实现,在每个时间步选择最可能的字符,因此是贪心的并且是局部最优的。[*CTC波束搜索解码器*](https://arxiv.org/abs/1408.2873)另外使用了启发式广度优先图搜索以达到近似全局最优; 它也需要预先训练的KenLM语言模型以获得更好的评分和排名。解码器类型可以用参数`--decoding_method`设置。 获得更多帮助: @@ -292,13 +292,13 @@ python infer.py --help 要定量评估模型的性能,请运行: -- GPU版本评估 +- GPU 版本评估 ```bash CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 python test.py ``` -- CPU版本评估 +- CPU 版本评估 ```bash python test.py --use_gpu False @@ -319,7 +319,7 @@ python test.py --help `tools/tune.py`会进行2维网格查找超参数$\alpha$和$\beta$。你必须提供$\alpha$和$\beta$的范围,以及尝试的次数。 -- 带GPU版的调整: +- GPU 版的调整: ```bash CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ @@ -332,21 +332,21 @@ python test.py --help --num_betas 8 ``` -- CPU版的调整: +- CPU 版的调整: ```bash python tools/tune.py --use_gpu False ``` -网格搜索将会在超参数空间的每个点处打印出WER(误字率)或者CER(字符错误率),并且可绘出误差曲面。一个合适的超参数范围应包括WER/CER误差表面的全局最小值,如下图所示。 +网格搜索将会在超参数空间的每个点处打印出 WER (误字率)或者 CER (字符错误率),并且可绘出误差曲面。一个合适的超参数范围应包括 WER/CER 误差表面的全局最小值,如下图所示。


调整LibriSpeech的dev-clean集合的误差曲面示例

-通常,如图所示,语言模型权重($\alpha$)的变化显著影响CTC波束搜索解码器的性能。更好的方法是首先调整多批数据(可指定数量)以找出适当的超参数范围,然后更改为完整的验证集以进行精确调整。 +通常,如图所示,语言模型权重($\alpha$)的变化显著影响 CTC波束搜索解码器的性能。更好的方法是首先调整多批数据(可指定数量)以找出适当的超参数范围,然后更改为完整的验证集以进行精确调整。 -调整之后,您可以在推理和评价模块中重置$\alpha$和$\beta$,以检查它们是否真的有助于提高ASR性能。更多帮助如下: +调整之后,您可以在推理和评价模块中重置$\alpha$和$\beta$,以检查它们是否真的有助于提高 ASR 性能。更多帮助如下: ```bash python tune.py --help @@ -355,23 +355,23 @@ python tune.py --help ## 在Docker容器上运行 -Docker是一个开源工具,用于在孤立的环境中构建、发布和运行分布式应用程序。此项目的Docker镜像已在[hub.docker.com](https://hub.docker.com)中提供,并安装了所有依赖项,其中包括预先构建的PaddlePaddle,CTC解码器以及其他必要的Python和第三方库。这个Docker映像需要NVIDIA GPU的支持,所以请确保它的可用性并已完成[nvidia-docker](https://github.com/NVIDIA/nvidia-docker)的安装。 +Docker 是一个开源工具,用于在孤立的环境中构建、发布和运行分布式应用程序。此项目的 Docker 镜像已在[hub.docker.com](https://hub.docker.com)中提供,并安装了所有依赖项,其中包括预先构建的PaddlePaddle,CTC解码器以及其他必要的 Python 和第三方库。这个 Docker 映像需要NVIDIA GPU的支持,所以请确保它的可用性并已完成[nvidia-docker](https://github.com/NVIDIA/nvidia-docker)的安装。 -采取以下步骤来启动Docker镜像: +采取以下步骤来启动 Docker 镜像: -- 下载Docker镜像 +- 下载 Docker 镜像 ```bash nvidia-docker pull hub.baidubce.com/paddlepaddle/deep_speech_fluid:latest-gpu ``` -- git clone这个资源库 +- git clone 这个资源库 ``` git clone https://github.com/PaddlePaddle/DeepSpeech.git ``` -- 运行Docker镜像 +- 运行 Docker 镜像 ```bash sudo nvidia-docker run -it -v $(pwd)/DeepSpeech:/DeepSpeech hub.baidubce.com/paddlepaddle/deep_speech_fluid:latest-gpu /bin/bash @@ -382,11 +382,11 @@ sudo nvidia-docker run -it -v $(pwd)/DeepSpeech:/DeepSpeech hub.baidubce.com/pad ## 训练普通话语言 -普通话语言训练与英语训练的关键步骤相同,我们提供了一个使用Aishell进行普通话训练的例子```examples/aishell```。如上所述,请执行```sh run_data.sh```, ```sh run_train.sh```, ```sh run_test.sh```和```sh run_infer.sh```做相应的数据准备,训练,测试和推断。我们还准备了一个预训练过的模型(执行./models/aishell/download_model.sh下载)供用户使用```run_infer_golden.sh```和```run_test_golden.sh```来。请注意,与英语语言模型不同,普通话语言模型是基于汉字的,请运行```tools/tune.py```来查找最佳设置。 +普通话语言训练与英语训练的关键步骤相同,我们提供了一个使用 Aishell 进行普通话训练的例子```examples/aishell```。如上所述,请执行```sh run_data.sh```, ```sh run_train.sh```, ```sh run_test.sh```和```sh run_infer.sh```做相应的数据准备,训练,测试和推断。我们还准备了一个预训练过的模型(执行./models/aishell/download_model.sh下载)供用户使用```run_infer_golden.sh```和```run_test_golden.sh```来。请注意,与英语语言模型不同,普通话语言模型是基于汉字的,请运行```tools/tune.py```来查找最佳设置。 ##用自己的声音尝试现场演示 -到目前为止,一个ASR模型已经训练完毕,并且用现有的音频文件进行了定性测试(`infer.py`)和定量测试(`test.py`)。但目前还没有用你自己的声音进行测试。`deploy/demo_english_server.py`和`deploy/demo_client.py`能够快速构建一个利用已训练好的模型对ASR引擎进行实时演示的系统,使你能够用自己的语音测试和演示。 +到目前为止,一个 ASR 模型已经训练完毕,并且用现有的音频文件进行了定性测试(`infer.py`)和定量测试(`test.py`)。但目前还没有用你自己的声音进行测试。`deploy/demo_english_server.py`和`deploy/demo_client.py`能够快速构建一个利用已训练好的模型对ASR引擎进行实时演示的系统,使你能够用自己的语音测试和演示。 要启动演示服务,请在控制台中运行: @@ -397,9 +397,9 @@ python deploy/demo_server.py \ --host_port 8086 ``` -对于运行demo客户端的机器(可能不是同一台机器),请在继续之前执行以下安装。 +对于运行 demo 客户端的机器(可能不是同一台机器),请在继续之前执行以下安装。 -比如,对于MAC OS X机器: +比如,对于 MAC OS X 机器: ```bash brew install portaudio diff --git a/data_utils/data.py b/data_utils/data.py index 72511b811..0fb2a88ba 100644 --- a/data_utils/data.py +++ b/data_utils/data.py @@ -57,7 +57,7 @@ class DataGenerator(object): converting to index sequence. :type keep_transcription_text: bool :param place: The place to run the program. - :type place: CPU or GPU + :type place: CPUPlace or CUDAPlace :param is_training: If set to True, generate text data for training, otherwise, generate text data for infer. :type is_training: bool diff --git a/deploy/demo_server.py b/deploy/demo_server.py index 0f6089892..68fcb245f 100644 --- a/deploy/demo_server.py +++ b/deploy/demo_server.py @@ -162,7 +162,7 @@ def start_server(): num_rnn_layers=args.num_rnn_layers, rnn_layer_size=args.rnn_layer_size, use_gru=args.use_gru, - init_from_pretrain_model=args.model_path, + init_from_pretrained_model=args.model_path, place=place, share_rnn_weights=args.share_rnn_weights) diff --git a/examples/aishell/run_train.sh b/examples/aishell/run_train.sh index 48b49c416..335473fcf 100644 --- a/examples/aishell/run_train.sh +++ b/examples/aishell/run_train.sh @@ -3,7 +3,7 @@ cd ../.. > /dev/null # train model -# if you wish to resume from an exists model, uncomment --init_from_pretrain_model +# if you wish to resume from an exists model, uncomment --init_from_pretrained_model export FLAGS_sync_nccl_allreduce=0 CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ python -u train.py \ diff --git a/examples/librispeech/run_train.sh b/examples/librispeech/run_train.sh index 5917a1d58..a568bf221 100644 --- a/examples/librispeech/run_train.sh +++ b/examples/librispeech/run_train.sh @@ -3,7 +3,7 @@ cd ../.. > /dev/null # train model -# if you wish to resume from an exists model, uncomment --init_from_pretrain_model +# if you wish to resume from an exists model, uncomment --init_from_pretrained_model export FLAGS_sync_nccl_allreduce=0 CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ diff --git a/examples/tiny/run_train.sh b/examples/tiny/run_train.sh index 9d436fb64..95ccd2bc6 100644 --- a/examples/tiny/run_train.sh +++ b/examples/tiny/run_train.sh @@ -3,7 +3,7 @@ cd ../.. > /dev/null # train model -# if you wish to resume from an exists model, uncomment --init_from_pretrain_model +# if you wish to resume from an exists model, uncomment --init_from_pretrained_model export FLAGS_sync_nccl_allreduce=0 CUDA_VISIBLE_DEVICES=0,1,2,3 \ python -u train.py \ diff --git a/infer.py b/infer.py index 4dd1f275a..e43aa5266 100644 --- a/infer.py +++ b/infer.py @@ -12,6 +12,7 @@ import functools import paddle.fluid as fluid from data_utils.data import DataGenerator from model_utils.model import DeepSpeech2Model +from model_utils.model_check import check_cuda, check_version from utils.error_rate import wer, cer from utils.utility import add_arguments, print_arguments @@ -66,6 +67,12 @@ args = parser.parse_args() def infer(): """Inference for DeepSpeech2.""" + + # check if set use_gpu=True in paddlepaddle cpu version + check_cuda(args.use_gpu) + # check if paddlepaddle version is satisfied + check_version() + if args.use_gpu: place = fluid.CUDAPlace(0) else: @@ -94,7 +101,7 @@ def infer(): use_gru=args.use_gru, share_rnn_weights=args.share_rnn_weights, place=place, - init_from_pretrain_model=args.model_path) + init_from_pretrained_model=args.model_path) # decoders only accept string encoded in utf-8 vocab_list = [chars.encode("utf-8") for chars in data_generator.vocab_list] diff --git a/model_utils/model.py b/model_utils/model.py index ecc3f28a2..fe1ae43d0 100644 --- a/model_utils/model.py +++ b/model_utils/model.py @@ -44,7 +44,7 @@ class DeepSpeech2Model(object): for GRU, weight sharing is not supported. :type share_rnn_weights: bool :param place: Program running place. - :type place: CPU or GPU + :type place: CPUPlace or CUDAPlace :param init_from_pretrained_model: Pretrained model path. If None, will train from stratch. :type init_from_pretrained_model: string|None @@ -60,7 +60,7 @@ class DeepSpeech2Model(object): use_gru=False, share_rnn_weights=True, place=fluid.CPUPlace(), - init_from_pretrain_model=None, + init_from_pretrained_model=None, output_model_dir=None): self._vocab_size = vocab_size self._num_conv_layers = num_conv_layers @@ -69,7 +69,7 @@ class DeepSpeech2Model(object): self._use_gru = use_gru self._share_rnn_weights = share_rnn_weights self._place = place - self._init_from_pretrain_model = init_from_pretrain_model + self._init_from_pretrained_model = init_from_pretrained_model self._output_model_dir = output_model_dir self._ext_scorer = None self.logger = logging.getLogger("") @@ -90,13 +90,14 @@ class DeepSpeech2Model(object): if not is_infer: input_fields = { 'names': ['audio_data', 'text_data', 'seq_len_data', 'masks'], - 'shapes': [[-1, 161, 161], [-1, 1], [-1, 1], [-1, 32, 81, 1]], + 'shapes': + [[None, 161, None], [None, 1], [None, 1], [None, 32, 81, None]], 'dtypes': ['float32', 'int32', 'int64', 'float32'], 'lod_levels': [0, 1, 0, 0] } inputs = [ - fluid.layers.data( + fluid.data( name=input_fields['names'][i], shape=input_fields['shapes'][i], dtype=input_fields['dtypes'][i], @@ -104,7 +105,7 @@ class DeepSpeech2Model(object): for i in range(len(input_fields['names'])) ] - reader = fluid.io.PyReader( + reader = fluid.io.DataLoader.from_generator( feed_list=inputs, capacity=64, iterable=False, @@ -112,16 +113,19 @@ class DeepSpeech2Model(object): (audio_data, text_data, seq_len_data, masks) = inputs else: - audio_data = fluid.layers.data( + audio_data = fluid.data( name='audio_data', - shape=[-1, 161, 161], + shape=[None, 161, None], dtype='float32', lod_level=0) - seq_len_data = fluid.layers.data( - name='seq_len_data', shape=[-1, 1], dtype='int64', lod_level=0) - masks = fluid.layers.data( + seq_len_data = fluid.data( + name='seq_len_data', + shape=[None, 1], + dtype='int64', + lod_level=0) + masks = fluid.data( name='masks', - shape=[-1, 32, 81, 1], + shape=[None, 32, 81, None], dtype='float32', lod_level=0) text_data = None @@ -141,26 +145,26 @@ class DeepSpeech2Model(object): share_rnn_weights=self._share_rnn_weights) return reader, log_probs, loss - def init_from_pretrain_model(self, exe, program): + def init_from_pretrained_model(self, exe, program): '''Init params from pretrain model. ''' - assert isinstance(self._init_from_pretrain_model, str) + assert isinstance(self._init_from_pretrained_model, str) - if not os.path.exists(self._init_from_pretrain_model): - print(self._init_from_pretrain_model) + if not os.path.exists(self._init_from_pretrained_model): + print(self._init_from_pretrained_model) raise Warning("The pretrained params do not exist.") return False fluid.io.load_params( exe, - self._init_from_pretrain_model, + self._init_from_pretrained_model, main_program=program, filename="params.pdparams") print("finish initing model from pretrained params from %s" % - (self._init_from_pretrain_model)) + (self._init_from_pretrained_model)) pre_epoch = 0 - dir_name = self._init_from_pretrain_model.split('_') + dir_name = self._init_from_pretrained_model.split('_') if len(dir_name) >= 2 and dir_name[-2].endswith('epoch') and dir_name[ -1].isdigit(): pre_epoch = int(dir_name[-1]) @@ -186,7 +190,7 @@ class DeepSpeech2Model(object): return True - def test(self, exe, dev_batch_reader, test_program, test_pyreader, + def test(self, exe, dev_batch_reader, test_program, test_reader, fetch_list): '''Test the model. @@ -196,14 +200,14 @@ class DeepSpeech2Model(object): :type dev_batch_reader: read generator :param test_program: The program of test. :type test_program: Program - :param test_pyreader: Pyreader of test. - :type test_pyreader: Pyreader + :param test_reader: Reader of test. + :type test_reader: Reader :param fetch_list: Fetch list. :type fetch_list: list :return: An output unnormalized log probability. :rtype: array ''' - test_pyreader.start() + test_reader.start() epoch_loss = [] while True: try: @@ -214,7 +218,7 @@ class DeepSpeech2Model(object): epoch_loss.extend(np.array(each_loss[0])) except fluid.core.EOFException: - test_pyreader.reset() + test_reader.reset() break return np.mean(np.array(epoch_loss)) @@ -274,7 +278,7 @@ class DeepSpeech2Model(object): startup_prog = fluid.Program() with fluid.program_guard(train_program, startup_prog): with fluid.unique_name.guard(): - train_pyreader, log_probs, ctc_loss = self.create_network() + train_reader, log_probs, ctc_loss = self.create_network() # prepare optimizer optimizer = fluid.optimizer.AdamOptimizer( learning_rate=fluid.layers.exponential_decay( @@ -290,7 +294,7 @@ class DeepSpeech2Model(object): test_prog = fluid.Program() with fluid.program_guard(test_prog, startup_prog): with fluid.unique_name.guard(): - test_pyreader, _, ctc_loss = self.create_network() + test_reader, _, ctc_loss = self.create_network() test_prog = test_prog.clone(for_test=True) @@ -299,8 +303,8 @@ class DeepSpeech2Model(object): # init from some pretrain models, to better solve the current task pre_epoch = 0 - if self._init_from_pretrain_model: - pre_epoch = self.init_from_pretrain_model(exe, train_program) + if self._init_from_pretrained_model: + pre_epoch = self.init_from_pretrained_model(exe, train_program) build_strategy = compiler.BuildStrategy() exec_strategy = fluid.ExecutionStrategy() @@ -312,12 +316,12 @@ class DeepSpeech2Model(object): build_strategy=build_strategy, exec_strategy=exec_strategy) - train_pyreader.decorate_batch_generator(train_batch_reader) - test_pyreader.decorate_batch_generator(dev_batch_reader) + train_reader.set_batch_generator(train_batch_reader) + test_reader.set_batch_generator(dev_batch_reader) # run train for epoch_id in range(num_epoch): - train_pyreader.start() + train_reader.start() epoch_loss = [] time_begin = time.time() batch_id = 0 @@ -346,7 +350,7 @@ class DeepSpeech2Model(object): batch_id = batch_id + 1 except fluid.core.EOFException: - train_pyreader.reset() + train_reader.reset() break time_end = time.time() used_time = time_end - time_begin @@ -359,7 +363,7 @@ class DeepSpeech2Model(object): exe, dev_batch_reader=dev_batch_reader, test_program=test_prog, - test_pyreader=test_pyreader, + test_reader=test_reader, fetch_list=[ctc_loss]) print( "--------Time: %f sec, epoch: %d, train loss: %f, test loss: %f" @@ -402,10 +406,10 @@ class DeepSpeech2Model(object): exe = fluid.Executor(self._place) exe.run(startup_prog) - # init param from pretrain_model - if not self._init_from_pretrain_model: + # init param from pretrained_model + if not self._init_from_pretrained_model: exit("No pretrain model file path!") - self.init_from_pretrain_model(exe, infer_program) + self.init_from_pretrained_model(exe, infer_program) infer_results = [] time_begin = time.time() diff --git a/model_utils/model_check.py b/model_utils/model_check.py new file mode 100644 index 000000000..bf2c424fd --- /dev/null +++ b/model_utils/model_check.py @@ -0,0 +1,49 @@ +# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import paddle +import paddle.fluid as fluid + + +def check_cuda(use_cuda, err = \ + "\nYou can not set use_cuda = True in the model because you are using paddlepaddle-cpu.\n \ + Please: 1. Install paddlepaddle-gpu to run your models on GPU or 2. Set use_cuda = False to run models on CPU.\n" + ): + """ + Log error and exit when set use_gpu=true in paddlepaddle + cpu version. + """ + try: + if use_cuda == True and fluid.is_compiled_with_cuda() == False: + print(err) + sys.exit(1) + except Exception as e: + pass + + +def check_version(): + """ + Log error and exit when the installed version of paddlepaddle is + not satisfied. + """ + err = "PaddlePaddle version 1.6 or higher is required, " \ + "or a suitable develop version is satisfied as well. \n" \ + "Please make sure the version is good with your code." \ + + try: + fluid.require_version('1.6.0') + except Exception as e: + print(err) + sys.exit(1) diff --git a/model_utils/network.py b/model_utils/network.py index 0ba3a9161..3a4f1dc38 100644 --- a/model_utils/network.py +++ b/model_utils/network.py @@ -61,17 +61,17 @@ def conv_bn_layer(input, filter_size, num_channels_in, num_channels_out, stride, def simple_rnn(input, size, param_attr=None, bias_attr=None, is_reverse=False): '''A simple rnn layer. - :param input:input layer. - :type input:Variable - :param size:Number of RNN cells. - :type size:int - :param param_attr:Parameter properties of hidden layer weights that + :param input: input layer. + :type input: Variable + :param size: Dimension of RNN cells. + :type size: int + :param param_attr: Parameter properties of hidden layer weights that can be learned - :type param_attr:ParamAttr - :param bias_attr:Bias properties of hidden layer weights that can be learned - :type bias_attr:ParamAttr - :param is_reverse:Whether to calculate the inverse RNN - :type is_reverse:bool + :type param_attr: ParamAttr + :param bias_attr: Bias properties of hidden layer weights that can be learned + :type bias_attr: ParamAttr + :param is_reverse: Whether to calculate the inverse RNN + :type is_reverse: bool :return: A simple RNN layer. :rtype: Variable ''' @@ -112,7 +112,7 @@ def bidirectional_simple_rnn_bn_layer(name, input, size, share_weights): :type name: string :param input: Input layer. :type input: Variable - :param size: Number of RNN cells. + :param size: Dimension of RNN cells. :type size: int :param share_weights: Whether to share input-hidden weights between forward and backward directional RNNs. @@ -206,7 +206,7 @@ def bidirectional_gru_bn_layer(name, input, size, act): :type name: string :param input: Input layer. :type input: Variable - :param size: Number of GRU cells. + :param size: Dimension of GRU cells. :type size: int :param act: Activation type. :type act: string @@ -317,7 +317,7 @@ def rnn_group(input, size, num_stacks, num_conv_layers, use_gru, """RNN group with stacked bidirectional simple RNN or GRU layers. :param input: Input layer. :type input: Variable - :param size: Number of RNN cells in each layer. + :param size: Dimension of RNN cells in each layer. :type size: int :param num_stacks: Number of stacked rnn layers. :type num_stacks: int @@ -373,7 +373,7 @@ def deep_speech_v2_network(audio_data, :type num_conv_layers: int :param num_rnn_layers: Number of stacking RNN layers. :type num_rnn_layers: int - :param rnn_size: RNN layer size (number of RNN cells). + :param rnn_size: RNN layer size (dimension of RNN cells). :type rnn_size: int :param use_gru: Use gru if set True. Use simple rnn if set False. :type use_gru: bool diff --git a/test.py b/test.py index 44307ba83..12df55219 100644 --- a/test.py +++ b/test.py @@ -8,6 +8,7 @@ import functools import paddle.fluid as fluid from data_utils.data import DataGenerator from model_utils.model import DeepSpeech2Model +from model_utils.model_check import check_cuda, check_version from utils.error_rate import char_errors, word_errors from utils.utility import add_arguments, print_arguments @@ -62,6 +63,12 @@ args = parser.parse_args() def evaluate(): """Evaluate on whole test data for DeepSpeech2.""" + + # check if set use_gpu=True in paddlepaddle cpu version + check_cuda(args.use_gpu) + # check if paddlepaddle version is satisfied + check_version() + if args.use_gpu: place = fluid.CUDAPlace(0) else: @@ -89,7 +96,7 @@ def evaluate(): use_gru=args.use_gru, share_rnn_weights=args.share_rnn_weights, place=place, - init_from_pretrain_model=args.model_path) + init_from_pretrained_model=args.model_path) # decoders only accept string encoded in utf-8 vocab_list = [chars.encode("utf-8") for chars in data_generator.vocab_list] diff --git a/tools/tune.py b/tools/tune.py index 843df0c6f..7996e4d53 100644 --- a/tools/tune.py +++ b/tools/tune.py @@ -103,7 +103,7 @@ def tune(): rnn_layer_size=args.rnn_layer_size, use_gru=args.use_gru, place=place, - init_from_pretrain_model=args.model_path, + init_from_pretrained_model=args.model_path, share_rnn_weights=args.share_rnn_weights) # decoders only accept string encoded in utf-8 diff --git a/train.py b/train.py index 0d409d939..5dae4ccdd 100644 --- a/train.py +++ b/train.py @@ -7,6 +7,7 @@ import argparse import functools import io from model_utils.model import DeepSpeech2Model +from model_utils.model_check import check_cuda, check_version from data_utils.data import DataGenerator from utils.utility import add_arguments, print_arguments @@ -34,7 +35,7 @@ add_arg('use_gru', bool, False, "Use GRUs instead of simple RNNs.") add_arg('is_local', bool, True, "Use pserver or not.") add_arg('share_rnn_weights',bool, True, "Share input-hidden weights across " "bi-directional RNNs. Not for GRU.") -add_arg('init_from_pretrain_model',str, +add_arg('init_from_pretrained_model',str, None, "If None, the training starts from scratch, " "otherwise, it resumes from the pre-trained model.") @@ -71,6 +72,12 @@ args = parser.parse_args() def train(): """DeepSpeech2 training.""" + + # check if set use_gpu=True in paddlepaddle cpu version + check_cuda(args.use_gpu) + # check if paddlepaddle version is satisfied + check_version() + if args.use_gpu: place = fluid.CUDAPlace(0) else: @@ -93,7 +100,7 @@ def train(): train_batch_reader = train_generator.batch_reader_creator( manifest_path=args.train_manifest, batch_size=args.batch_size, - sortagrad=args.use_sortagrad if args.init_from_pretrain_model is None else False, + sortagrad=args.use_sortagrad if args.init_from_pretrained_model is None else False, shuffle_method=args.shuffle_method) dev_batch_reader = dev_generator.batch_reader_creator( manifest_path=args.dev_manifest, @@ -109,7 +116,7 @@ def train(): use_gru=args.use_gru, share_rnn_weights=args.share_rnn_weights, place=place, - init_from_pretrain_model=args.init_from_pretrain_model, + init_from_pretrained_model=args.init_from_pretrained_model, output_model_dir=args.output_model_dir) ds2_model.train(