From 9b4786c39685ddb60a38385ef44ad01655890788 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Tue, 14 Sep 2021 09:54:27 +0000 Subject: [PATCH 01/33] more doc for egs --- deepspeech/exps/u2/bin/train.py | 5 +- doc/images/multi_gpu_speedup.png | Bin 211490 -> 0 bytes doc/images/tuning_error_surface.png | Bin 110461 -> 0 bytes doc/src/benchmark.md | 16 --- {doc => docs}/images/ds2offlineModel.png | Bin {doc => docs}/images/ds2onlineModel.png | Bin {doc => docs}/src/augmentation.md | 0 {doc => docs}/src/data_preparation.md | 0 {doc => docs}/src/deepspeech_architecture.md | 0 {doc => docs}/src/feature_list.md | 0 {doc => docs}/src/getting_started.md | 0 {doc => docs}/src/install.md | 0 {doc => docs}/src/ngram_lm.md | 0 {doc => docs}/src/reference.md | 0 {doc => docs}/src/released_model.md | 0 examples/cc-cedict/README.md | 58 +++++++++++ examples/chinese_g2p/README.md | 5 - examples/{chinese_g2p => g2p}/.gitignore | 0 examples/g2p/README.md | 3 + examples/g2p/zh/README.md | 93 ++++++++++++++++++ .../zh}/local/convert_transcription.py | 0 .../zh}/local/extract_pinyin_label.py | 0 .../zh}/local/ignore_sandhi.py | 0 .../zh}/local/prepare_dataset.sh | 0 examples/{chinese_g2p => g2p/zh}/path.sh | 2 +- .../{chinese_g2p => g2p/zh}/requirements.txt | 0 examples/{chinese_g2p => g2p/zh}/run.sh | 7 +- examples/ngram_lm/READEME.md | 3 + examples/ngram_lm/s0/.gitignore | 1 + examples/ngram_lm/s0/README.md | 89 +++++++++++++++++ examples/spm/README.md | 89 +++++++++++++++++ examples/text_normalization/README.md | 3 - examples/tn/.gitignore | 1 + examples/tn/README.md | 36 +++++++ .../data/sentences.txt | 0 .../local/test_normalization.py | 0 examples/{text_normalization => tn}/path.sh | 0 examples/{text_normalization => tn}/run.sh | 0 38 files changed, 381 insertions(+), 30 deletions(-) delete mode 100755 doc/images/multi_gpu_speedup.png delete mode 100644 doc/images/tuning_error_surface.png delete mode 100644 doc/src/benchmark.md rename {doc => docs}/images/ds2offlineModel.png (100%) rename {doc => docs}/images/ds2onlineModel.png (100%) rename {doc => docs}/src/augmentation.md (100%) rename {doc => docs}/src/data_preparation.md (100%) rename {doc => docs}/src/deepspeech_architecture.md (100%) rename {doc => docs}/src/feature_list.md (100%) rename {doc => docs}/src/getting_started.md (100%) rename {doc => docs}/src/install.md (100%) rename {doc => docs}/src/ngram_lm.md (100%) rename {doc => docs}/src/reference.md (100%) rename {doc => docs}/src/released_model.md (100%) delete mode 100644 examples/chinese_g2p/README.md rename examples/{chinese_g2p => g2p}/.gitignore (100%) create mode 100644 examples/g2p/README.md create mode 100644 examples/g2p/zh/README.md rename examples/{chinese_g2p => g2p/zh}/local/convert_transcription.py (100%) rename examples/{chinese_g2p => g2p/zh}/local/extract_pinyin_label.py (100%) rename examples/{chinese_g2p => g2p/zh}/local/ignore_sandhi.py (100%) rename examples/{chinese_g2p => g2p/zh}/local/prepare_dataset.sh (100%) rename examples/{chinese_g2p => g2p/zh}/path.sh (82%) rename examples/{chinese_g2p => g2p/zh}/requirements.txt (100%) rename examples/{chinese_g2p => g2p/zh}/run.sh (82%) create mode 100644 examples/ngram_lm/READEME.md create mode 100644 examples/ngram_lm/s0/.gitignore delete mode 100644 examples/text_normalization/README.md create mode 100644 examples/tn/.gitignore create mode 100644 examples/tn/README.md rename examples/{text_normalization => tn}/data/sentences.txt (100%) rename examples/{text_normalization => tn}/local/test_normalization.py (100%) rename examples/{text_normalization => tn}/path.sh (100%) rename examples/{text_normalization => tn}/run.sh (100%) diff --git a/deepspeech/exps/u2/bin/train.py b/deepspeech/exps/u2/bin/train.py index bd1aeb9ef..fef615ce3 100644 --- a/deepspeech/exps/u2/bin/train.py +++ b/deepspeech/exps/u2/bin/train.py @@ -18,11 +18,10 @@ import os from paddle import distributed as dist from deepspeech.exps.u2.config import get_cfg_defaults -# from deepspeech.exps.u2.trainer import U2Trainer as Trainer +from deepspeech.exps.u2.model import U2Trainer as Trainer from deepspeech.training.cli import default_argument_parser from deepspeech.utils.utility import print_arguments - -from deepspeech.exps.u2.model import U2Trainer as Trainer +# from deepspeech.exps.u2.trainer import U2Trainer as Trainer def main_sp(config, args): diff --git a/doc/images/multi_gpu_speedup.png b/doc/images/multi_gpu_speedup.png deleted file mode 100755 index 286de51519203bb070ce9a539a21627808b7403c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 211490 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 diff --git a/doc/images/tuning_error_surface.png b/doc/images/tuning_error_surface.png deleted file mode 100644 index 2204cee2f5204d1d2d2e53fab8cdd0a1cb9ac47d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110461 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 - -| # of GPU | Acceleration Rate | -| -------- | --------------: | -| 1 | 1.00 X | -| 2 | 1.98 X | -| 4 | 3.73 X | -| 8 | 6.95 X | - -`utils/profile.sh` provides such a demo profiling tool, you can change it as need. diff --git a/doc/images/ds2offlineModel.png b/docs/images/ds2offlineModel.png similarity index 100% rename from doc/images/ds2offlineModel.png rename to docs/images/ds2offlineModel.png diff --git a/doc/images/ds2onlineModel.png b/docs/images/ds2onlineModel.png similarity index 100% rename from doc/images/ds2onlineModel.png rename to docs/images/ds2onlineModel.png diff --git a/doc/src/augmentation.md b/docs/src/augmentation.md similarity index 100% rename from doc/src/augmentation.md rename to docs/src/augmentation.md diff --git a/doc/src/data_preparation.md b/docs/src/data_preparation.md similarity index 100% rename from doc/src/data_preparation.md rename to docs/src/data_preparation.md diff --git a/doc/src/deepspeech_architecture.md b/docs/src/deepspeech_architecture.md similarity index 100% rename from doc/src/deepspeech_architecture.md rename to docs/src/deepspeech_architecture.md diff --git a/doc/src/feature_list.md b/docs/src/feature_list.md similarity index 100% rename from doc/src/feature_list.md rename to docs/src/feature_list.md diff --git a/doc/src/getting_started.md b/docs/src/getting_started.md similarity index 100% rename from doc/src/getting_started.md rename to docs/src/getting_started.md diff --git a/doc/src/install.md b/docs/src/install.md similarity index 100% rename from doc/src/install.md rename to docs/src/install.md diff --git a/doc/src/ngram_lm.md b/docs/src/ngram_lm.md similarity index 100% rename from doc/src/ngram_lm.md rename to docs/src/ngram_lm.md diff --git a/doc/src/reference.md b/docs/src/reference.md similarity index 100% rename from doc/src/reference.md rename to docs/src/reference.md diff --git a/doc/src/released_model.md b/docs/src/released_model.md similarity index 100% rename from doc/src/released_model.md rename to docs/src/released_model.md diff --git a/examples/cc-cedict/README.md b/examples/cc-cedict/README.md index e69de29bb..513fca533 100644 --- a/examples/cc-cedict/README.md +++ b/examples/cc-cedict/README.md @@ -0,0 +1,58 @@ +# [CC-CEDICT](https://cc-cedict.org/wiki/) + +What is CC-CEDICT? +CC-CEDICT is a continuation of the CEDICT project. +The objective of the CEDICT project was to create an online, downloadable (as opposed to searchable-only) public-domain Chinese-English dictionary. +CEDICT was started by Paul Andrew Denisowski in October 1997. +For the most part, the project is modeled on Jim Breen's highly successful EDICT (Japanese-English dictionary) project and is intended to be a collaborative effort, +with users providing entries and corrections to the main file. + + +## Parse CC-CEDICT to Json format + +1. Parse to Json + +``` +run.sh +``` + +2. Result + +``` +exp/ +|-- cedict +`-- cedict.json + +0 directories, 2 files +``` + +``` +4c4bffc84e24467fe1b2ea9ba37ed6b6 exp/cedict +3adf504dacd13886f88cc9fe3b37c75d exp/cedict.json +``` + +``` +==> exp/cedict <== +# CC-CEDICT +# Community maintained free Chinese-English dictionary. +# +# Published by MDBG +# +# License: +# Creative Commons Attribution-ShareAlike 4.0 International License +# https://creativecommons.org/licenses/by-sa/4.0/ +# +# Referenced works: + +==> exp/cedict.json <== +{"traditional": "2019\u51a0\u72c0\u75c5\u6bd2\u75c5", "simplified": "2019\u51a0\u72b6\u75c5\u6bd2\u75c5", "pinyin": "er4 ling2 yi1 jiu3 guan1 zhuang4 bing4 du2 bing4", "english": "COVID-19, the coronavirus disease identified in 2019"} +{"traditional": "21\u4e09\u9ad4\u7d9c\u5408\u75c7", "simplified": "21\u4e09\u4f53\u7efc\u5408\u75c7", "pinyin": "er4 shi2 yi1 san1 ti3 zong1 he2 zheng4", "english": "trisomy"} +{"traditional": "3C", "simplified": "3C", "pinyin": "san1 C", "english": "abbr. for computers, communications, and consumer electronics"} +{"traditional": "3P", "simplified": "3P", "pinyin": "san1 P", "english": "(slang) threesome"} +{"traditional": "3Q", "simplified": "3Q", "pinyin": "san1 Q", "english": "(Internet slang) thank you (loanword)"} +{"traditional": "421", "simplified": "421", "pinyin": "si4 er4 yi1", "english": "four grandparents, two parents and an only child"} +{"traditional": "502\u81a0", "simplified": "502\u80f6", "pinyin": "wu3 ling2 er4 jiao1", "english": "cyanoacrylate glue"} +{"traditional": "88", "simplified": "88", "pinyin": "ba1 ba1", "english": "(Internet slang) bye-bye (alternative for \u62dc\u62dc[bai2 bai2])"} +{"traditional": "996", "simplified": "996", "pinyin": "jiu3 jiu3 liu4", "english": "9am-9pm, six days a week (work schedule)"} +{"traditional": "A", "simplified": "A", "pinyin": "A", "english": "(slang) (Tw) to steal"} +``` diff --git a/examples/chinese_g2p/README.md b/examples/chinese_g2p/README.md deleted file mode 100644 index e3fdfe684..000000000 --- a/examples/chinese_g2p/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Download Baker dataset - -Baker dataset has to be downloaded mannually and moved to 'data/', because you will have to pass the CATTCHA from a browswe to download the dataset. - -Download URL https://test.data-baker.com/#/data/index/source. diff --git a/examples/chinese_g2p/.gitignore b/examples/g2p/.gitignore similarity index 100% rename from examples/chinese_g2p/.gitignore rename to examples/g2p/.gitignore diff --git a/examples/g2p/README.md b/examples/g2p/README.md new file mode 100644 index 000000000..4ec5922b3 --- /dev/null +++ b/examples/g2p/README.md @@ -0,0 +1,3 @@ +# G2P + +* zh - Chinese G2P diff --git a/examples/g2p/zh/README.md b/examples/g2p/zh/README.md new file mode 100644 index 000000000..de5573565 --- /dev/null +++ b/examples/g2p/zh/README.md @@ -0,0 +1,93 @@ +# G2P + +* WS +jieba +* G2P +pypinyin +* Tone sandhi +simple + +We recommend using [Paraket](https://github.com/PaddlePaddle/Parakeet] [TextFrontEnd](https://github.com/PaddlePaddle/Parakeet/blob/develop/parakeet/frontend/__init__.py) to do G2P. +The phoneme set should be changed, you can reference `examples/thchs30/a0/data/dict/syllable.lexicon`. + +## Download Baker dataset + +[Baker](https://test.data-baker.com/#/data/index/source) dataset has to be downloaded mannually and moved to './data', +because you will have to pass the `CATTCHA` from a browswe to download the dataset. + + +## RUN + +``` +. path.sh +./run.sh +``` + +## Result + +``` +exp/ +|-- 000001-010000.txt +|-- ref.pinyin +|-- trans.jieba.pinyin +`-- trans.pinyin + +0 directories, 4 files +``` + +``` +4f5a368441eb16aaf43dc1972f8b63dd exp/000001-010000.txt +01707896391c2de9b6fc4a39654be942 exp/ref.pinyin +43380ef160f65a23a3a0544700aa49b8 exp/trans.jieba.pinyin +8e6ff1fc22d8e8584082e804e8bcdeb7 exp/trans.pinyin +``` + +``` +==> exp/000001-010000.txt <== +000001 卡尔普#2陪外孙#1玩滑梯#4。 + ka2 er2 pu3 pei2 wai4 sun1 wan2 hua2 ti1 +000002 假语村言#2别再#1拥抱我#4。 + jia2 yu3 cun1 yan2 bie2 zai4 yong1 bao4 wo3 +000003 宝马#1配挂#1跛骡鞍#3,貂蝉#1怨枕#2董翁榻#4。 + bao2 ma3 pei4 gua4 bo3 luo2 an1 diao1 chan2 yuan4 zhen3 dong3 weng1 ta4 +000004 邓小平#2与#1撒切尔#2会晤#4。 + deng4 xiao3 ping2 yu3 sa4 qie4 er3 hui4 wu4 +000005 老虎#1幼崽#2与#1宠物犬#1玩耍#4。 + lao2 hu3 you4 zai3 yu2 chong3 wu4 quan3 wan2 shua3 + +==> exp/ref.pinyin <== +000001 ka2 er2 pu3 pei2 wai4 sun1 wan2 hua2 ti1 +000002 jia2 yu3 cun1 yan2 bie2 zai4 yong1 bao4 wo3 +000003 bao2 ma3 pei4 gua4 bo3 luo2 an1 diao1 chan2 yuan4 zhen3 dong3 weng1 ta4 +000004 deng4 xiao3 ping2 yu3 sa4 qie4 er3 hui4 wu4 +000005 lao2 hu3 you4 zai3 yu2 chong3 wu4 quan3 wan2 shua3 +000006 shen1 chang2 yue1 wu2 chi3 er4 cun4 wu3 fen1 huo4 yi3 shang4 +000007 zhao4 di2 yue1 cao2 yun2 teng2 qu4 gui3 wu1 +000008 zhan2 pin3 sui1 you3 zhan3 yuan2 que4 tui2 +000009 yi2 san3 ju1 er2 tong2 he2 you4 tuo1 er2 tong2 wei2 zhu3 +000010 ke1 te4 ni1 shen1 chuan1 bao4 wen2 da4 yi1 + +==> exp/trans.jieba.pinyin <== +000001 ka3 er3 pu3 pei2 wai4 sun1 wan2 hua2 ti1 +000002 jia3 yu3 cun1 yan2 bie2 zai4 yong1 bao4 wo3 +000003 bao3 ma3 pei4 gua4 bo3 luo2 an1 diao1 chan2 yuan4 zhen3 dong3 weng1 ta4 +000004 deng4 xiao3 ping2 yu3 sa1 qie4 er3 hui4 wu4 +000005 lao3 hu3 you4 zai3 yu3 chong3 wu4 quan3 wan2 shua3 +000006 shen1 chang2 yue1 wu3 chi3 er4 cun4 wu3 fen1 huo4 yi3 shang4 +000007 zhao4 di2 yue1 cao2 yun2 teng2 qu4 gui3 wu1 +000008 zhan3 pin3 sui1 you3 zhan3 yuan2 que4 tui2 +000009 yi3 san3 ju1 er2 tong2 he2 you4 tuo1 er2 tong2 wei2 zhu3 +000010 ke1 te4 ni1 shen1 chuan1 bao4 wen2 da4 yi1 + +==> exp/trans.pinyin <== +000001 ka3 er3 pu3 pei2 wai4 sun1 wan2 hua2 ti1 +000002 jia3 yu3 cun1 yan2 bie2 zai4 yong1 bao4 wo3 +000003 bao3 ma3 pei4 gua4 bo3 luo2 an1 diao1 chan2 yuan4 zhen3 dong3 weng1 ta4 +000004 deng4 xiao3 ping2 yu3 sa1 qie4 er3 hui4 wu4 +000005 lao3 hu3 you4 zai3 yu3 chong3 wu4 quan3 wan2 shua3 +000006 shen1 chang2 yue1 wu3 chi3 er4 cun4 wu3 fen1 huo4 yi3 shang4 +000007 zhao4 di2 yue1 cao2 yun2 teng2 qu4 gui3 wu1 +000008 zhan3 pin3 sui1 you3 zhan3 yuan2 que4 tui2 +000009 yi3 san3 ju1 er2 tong2 he2 you4 tuo1 er2 tong2 wei2 zhu3 +000010 ke1 te4 ni1 shen1 chuan1 bao4 wen2 da4 yi1 +``` diff --git a/examples/chinese_g2p/local/convert_transcription.py b/examples/g2p/zh/local/convert_transcription.py similarity index 100% rename from examples/chinese_g2p/local/convert_transcription.py rename to examples/g2p/zh/local/convert_transcription.py diff --git a/examples/chinese_g2p/local/extract_pinyin_label.py b/examples/g2p/zh/local/extract_pinyin_label.py similarity index 100% rename from examples/chinese_g2p/local/extract_pinyin_label.py rename to examples/g2p/zh/local/extract_pinyin_label.py diff --git a/examples/chinese_g2p/local/ignore_sandhi.py b/examples/g2p/zh/local/ignore_sandhi.py similarity index 100% rename from examples/chinese_g2p/local/ignore_sandhi.py rename to examples/g2p/zh/local/ignore_sandhi.py diff --git a/examples/chinese_g2p/local/prepare_dataset.sh b/examples/g2p/zh/local/prepare_dataset.sh similarity index 100% rename from examples/chinese_g2p/local/prepare_dataset.sh rename to examples/g2p/zh/local/prepare_dataset.sh diff --git a/examples/chinese_g2p/path.sh b/examples/g2p/zh/path.sh similarity index 82% rename from examples/chinese_g2p/path.sh rename to examples/g2p/zh/path.sh index 482177dc6..f475ed833 100644 --- a/examples/chinese_g2p/path.sh +++ b/examples/g2p/zh/path.sh @@ -1,4 +1,4 @@ -export MAIN_ROOT=`realpath ${PWD}/../../` +export MAIN_ROOT=`realpath ${PWD}/../../../` export PATH=${MAIN_ROOT}:${MAIN_ROOT}/utils:${PATH} export LC_ALL=C diff --git a/examples/chinese_g2p/requirements.txt b/examples/g2p/zh/requirements.txt similarity index 100% rename from examples/chinese_g2p/requirements.txt rename to examples/g2p/zh/requirements.txt diff --git a/examples/chinese_g2p/run.sh b/examples/g2p/zh/run.sh similarity index 82% rename from examples/chinese_g2p/run.sh rename to examples/g2p/zh/run.sh index 8197dce4b..25b713110 100755 --- a/examples/chinese_g2p/run.sh +++ b/examples/g2p/zh/run.sh @@ -6,16 +6,19 @@ stage=-1 stop_stage=100 exp_dir=exp -data_dir=data +data=data source ${MAIN_ROOT}/utils/parse_options.sh || exit -1 mkdir -p ${exp_dir} +if [ $stage -le -1 ] && [ $stop_stage -ge -1 ];then + test -e ${data}/BZNSYP.rar || { echo "Please download BZNSYP.rar and put it in ${data}; exit -1; } +fi if [ $stage -le 0 ] && [ $stop_stage -ge 0 ];then echo "stage 0: Extracting Prosody Labeling" - bash local/prepare_dataset.sh --exp-dir ${exp_dir} --data-dir ${data_dir} + bash local/prepare_dataset.sh --exp-dir ${exp_dir} --data-dir ${data} fi # convert transcription in chinese into pinyin with pypinyin or jieba+pypinyin diff --git a/examples/ngram_lm/READEME.md b/examples/ngram_lm/READEME.md new file mode 100644 index 000000000..84e1380c3 --- /dev/null +++ b/examples/ngram_lm/READEME.md @@ -0,0 +1,3 @@ +# Ngram LM + +* s0 - kenlm ngram lm diff --git a/examples/ngram_lm/s0/.gitignore b/examples/ngram_lm/s0/.gitignore new file mode 100644 index 000000000..b20d93aa5 --- /dev/null +++ b/examples/ngram_lm/s0/.gitignore @@ -0,0 +1 @@ +data/lm diff --git a/examples/ngram_lm/s0/README.md b/examples/ngram_lm/s0/README.md index 698d7c290..65916ec54 100644 --- a/examples/ngram_lm/s0/README.md +++ b/examples/ngram_lm/s0/README.md @@ -2,6 +2,95 @@ Train chinese chararctor ngram lm by [kenlm](https://github.com/kpu/kenlm). +## Run ``` +. path.sh bash run.sh ``` + +## Results + +``` +exp/ +|-- text +|-- text.char.tn +|-- text.word.tn +|-- text_zh_char_o5_p0_1_2_4_4_a22_q8_b8.arpa +|-- text_zh_char_o5_p0_1_2_4_4_a22_q8_b8.arpa.klm.bin +|-- text_zh_word_o3_p0_0_0_a22_q8_b8.arpa +`-- text_zh_word_o3_p0_0_0_a22_q8_b8.arpa.klm.bin + +0 directories, 7 files +``` + +``` +3ae083627b9b6cef1a82d574d8483f97 exp/text +d97da252d2a63a662af22f98af30cb8c exp/text.char.tn +c18b03005bd094dbfd9b46442be361fd exp/text.word.tn +73dbf50097896eda33985e11e1ba9a3a exp/text_zh_char_o5_p0_1_2_4_4_a22_q8_b8.arpa +01334e2044c474b99c4f2ffbed790626 exp/text_zh_char_o5_p0_1_2_4_4_a22_q8_b8.arpa.klm.bin +36a42de548045b54662411ae7982c77f exp/text_zh_word_o3_p0_0_0_a22_q8_b8.arpa +332422803ffd73dd7ffd16cd2b0abcd5 exp/text_zh_word_o3_p0_0_0_a22_q8_b8.arpa.klm.bin +``` + +``` +==> exp/text <== +少先队员因该为老人让坐 +祛痘印可以吗?有效果吗? +不知这款牛奶口感怎样? 小孩子喝行吗! +是转基因油? +我家宝宝13斤用多大码的 +会起坨吗? +请问给送上楼吗? +亲是送赁上门吗 +送货时候有外包装没有还是直接发货过来 +会不会有坏的? + +==> exp/text.char.tn <== +少 先 队 员 因 该 为 老 人 让 坐 +祛 痘 印 可 以 吗 有 效 果 吗 +不 知 这 款 牛 奶 口 感 怎 样 小 孩 子 喝 行 吗 +是 转 基 因 油 +我 家 宝 宝 十 三 斤 用 多 大 码 的 +会 起 坨 吗 +请 问 给 送 上 楼 吗 +亲 是 送 赁 上 门 吗 +送 货 时 候 有 外 包 装 没 有 还 是 直 接 发 货 过 来 +会 不 会 有 坏 的 + +==> exp/text.word.tn <== +少先队员 因该 为 老人 让 坐 +祛痘 印 可以 吗 有 效果 吗 +不知 这 款 牛奶 口感 怎样 小孩子 喝行 吗 +是 转基因 油 +我家 宝宝 十三斤 用多大码 的 +会起 坨 吗 +请问 给 送 上楼 吗 +亲是 送赁 上门 吗 +送货 时候 有 外包装 没有 还是 直接 发货 过来 +会 不会 有坏 的 + +==> exp/text_zh_char_o5_p0_1_2_4_4_a22_q8_b8.arpa <== +\data\ +ngram 1=587 +ngram 2=395 +ngram 3=100 +ngram 4=2 +ngram 5=0 + +\1-grams: +-3.272324 0 +0 -0.36706257 + +==> exp/text_zh_word_o3_p0_0_0_a22_q8_b8.arpa <== +\data\ +ngram 1=689 +ngram 2=1398 +ngram 3=1506 + +\1-grams: +-3.1755018 0 +0 -0.23069073 +-1.2318869 0 +-3.067262 少先队员 -0.051341705 +``` diff --git a/examples/spm/README.md b/examples/spm/README.md index 3109d3ffb..fc4478ebb 100644 --- a/examples/spm/README.md +++ b/examples/spm/README.md @@ -1,7 +1,96 @@ # [SentencePiece Model](https://github.com/google/sentencepiece) +## Run Train a `spm` model for English tokenizer. ``` +. path.sh bash run.sh ``` + +## Results + +``` +data/ +└── lang_char + ├── input.bpe + ├── input.decode + ├── input.txt + ├── train_unigram100.model + ├── train_unigram100_units.txt + └── train_unigram100.vocab + +1 directory, 6 files +``` + +``` +b5a230c26c61db5c36f34e503102f936 data/lang_char/input.bpe +ec5a9b24acc35469229e41256ceaf77d data/lang_char/input.decode +ec5a9b24acc35469229e41256ceaf77d data/lang_char/input.txt +124bf3fe7ce3b73b1994234c15268577 data/lang_char/train_unigram100.model +0df2488cc8eaace95eb12713facb5cf0 data/lang_char/train_unigram100_units.txt +46360cac35c751310e8e8ffd3a034cb5 data/lang_char/train_unigram100.vocab +``` + +``` +==> data/lang_char/input.bpe <== +▁mi ster ▁quilter ▁ is ▁the ▁a p ost le ▁o f ▁the ▁mi d d le ▁c las s es ▁ and ▁we ▁ar e ▁g l a d ▁ to ▁we l c om e ▁h is ▁g o s pe l +▁ n or ▁ is ▁mi ster ▁quilter ' s ▁ma nne r ▁ l ess ▁in ter es t ing ▁tha n ▁h is ▁ma t ter +▁h e ▁ t e ll s ▁us ▁tha t ▁ at ▁ t h is ▁f es t ive ▁ s e ason ▁o f ▁the ▁ y e ar ▁w ith ▁ ch r is t m a s ▁ and ▁ro a s t ▁be e f ▁ l o om ing ▁be fore ▁us ▁ s i mile s ▁d r a w n ▁f r om ▁ e at ing ▁ and ▁it s ▁re s u l t s ▁o c c ur ▁m ost ▁re a di l y ▁ to ▁the ▁ mind +▁h e ▁ ha s ▁g r a v e ▁d o u b t s ▁w h e t h er ▁ s i r ▁f r e d er ic k ▁ l eig h to n ' s ▁w or k ▁ is ▁re all y ▁gre e k ▁a f ter ▁ all ▁ and ▁c a n ▁di s c o v er ▁in ▁it ▁b u t ▁li t t le ▁o f ▁ro ck y ▁it ha c a +▁li nne ll ' s ▁ p ic tur es ▁ar e ▁a ▁ s or t ▁o f ▁ u p ▁g u ar d s ▁ and ▁ at ▁ em ▁painting s ▁ and ▁m ason ' s ▁ e x q u is i t e ▁ i d y ll s ▁ar e ▁a s ▁ n at ion a l ▁a s ▁a ▁ j ing o ▁ p o em ▁mi ster ▁b i r k e t ▁f o ster ' s ▁ l and s c a pe s ▁ s mile ▁ at ▁on e ▁m u ch ▁in ▁the ▁ s a m e ▁w a y ▁tha t ▁mi ster ▁c ar k er ▁us e d ▁ to ▁f las h ▁h is ▁ t e e t h ▁ and ▁mi ster ▁ j o h n ▁c o ll i er ▁g ive s ▁h is ▁ s i t ter ▁a ▁ ch e er f u l ▁ s l a p ▁on ▁the ▁b a ck ▁be fore ▁h +e ▁ s a y s ▁li k e ▁a ▁ s ha m p o o er ▁in ▁a ▁ tur k is h ▁b at h ▁ n e x t ▁ma n +▁it ▁ is ▁o b v i o u s l y ▁ u nne c ess ar y ▁for ▁us ▁ to ▁ p o i n t ▁o u t ▁h o w ▁ l u m i n o u s ▁the s e ▁c rit ic is m s ▁ar e ▁h o w ▁d e l ic at e ▁in ▁ e x p r ess ion +▁on ▁the ▁g e n er a l ▁ p r i n c i p l es ▁o f ▁ar t ▁mi ster ▁quilter ▁w rit es ▁w ith ▁ e qual ▁ l u c i di t y +▁painting ▁h e ▁ t e ll s ▁us ▁ is ▁o f ▁a ▁di f f er e n t ▁ qual i t y ▁ to ▁ma t h em at ic s ▁ and ▁f i nish ▁in ▁ar t ▁ is ▁a d d ing ▁m or e ▁f a c t +▁a s ▁for ▁ e t ch ing s ▁the y ▁ar e ▁o f ▁ t w o ▁ k i n d s ▁b rit is h ▁ and ▁for eig n +▁h e ▁ l a ment s ▁m ost ▁b i t ter l y ▁the ▁di v or c e ▁tha t ▁ ha s ▁be e n ▁ma d e ▁be t w e e n ▁d e c or at ive ▁ar t ▁ and ▁w ha t ▁we ▁us u all y ▁c all ▁ p ic tur es ▁ma k es ▁the ▁c u s t om ar y ▁a p pe a l ▁ to ▁the ▁ las t ▁ j u d g ment ▁ and ▁re mind s ▁us ▁tha t ▁in ▁the ▁gre at ▁d a y s ▁o f ▁ar t ▁mi c ha e l ▁a n g e l o ▁w a s ▁the ▁f ur nish ing ▁ u p h o l ster er + +==> data/lang_char/input.decode <== +mister quilter is the apostle of the middle classes and we are glad to welcome his gospel +nor is mister quilter's manner less interesting than his matter +he tells us that at this festive season of the year with christmas and roast beef looming before us similes drawn from eating and its results occur most readily to the mind +he has grave doubts whether sir frederick leighton's work is really greek after all and can discover in it but little of rocky ithaca +linnell's pictures are a sort of up guards and at em paintings and mason's exquisite idylls are as national as a jingo poem mister birket foster's landscapes smile at one much in the same way that mister carker used to flash his teeth and mister john collier gives his sitter a cheerful slap on the back before he says like a shampooer in a turkish bath next man +it is obviously unnecessary for us to point out how luminous these criticisms are how delicate in expression +on the general principles of art mister quilter writes with equal lucidity +painting he tells us is of a different quality to mathematics and finish in art is adding more fact +as for etchings they are of two kinds british and foreign +he laments most bitterly the divorce that has been made between decorative art and what we usually call pictures makes the customary appeal to the last judgment and reminds us that in the great days of art michael angelo was the furnishing upholsterer + +==> data/lang_char/input.txt <== +mister quilter is the apostle of the middle classes and we are glad to welcome his gospel +nor is mister quilter's manner less interesting than his matter +he tells us that at this festive season of the year with christmas and roast beef looming before us similes drawn from eating and its results occur most readily to the mind +he has grave doubts whether sir frederick leighton's work is really greek after all and can discover in it but little of rocky ithaca +linnell's pictures are a sort of up guards and at em paintings and mason's exquisite idylls are as national as a jingo poem mister birket foster's landscapes smile at one much in the same way that mister carker used to flash his teeth and mister john collier gives his sitter a cheerful slap on the back before he says like a shampooer in a turkish bath next man +it is obviously unnecessary for us to point out how luminous these criticisms are how delicate in expression +on the general principles of art mister quilter writes with equal lucidity +painting he tells us is of a different quality to mathematics and finish in art is adding more fact +as for etchings they are of two kinds british and foreign +he laments most bitterly the divorce that has been made between decorative art and what we usually call pictures makes the customary appeal to the last judgment and reminds us that in the great days of art michael angelo was the furnishing upholsterer + +==> data/lang_char/train_unigram100_units.txt <== + 0 + 1 +' 2 +a 3 +all 4 +and 5 +ar 6 +ason 7 +at 8 +b 9 + +==> data/lang_char/train_unigram100.vocab <== + 0 + 0 + 0 +▁ -2.01742 +e -2.7203 +s -2.82989 +t -2.99689 +l -3.53267 +n -3.84935 +o -3.88229 +``` diff --git a/examples/text_normalization/README.md b/examples/text_normalization/README.md deleted file mode 100644 index dde0a5576..000000000 --- a/examples/text_normalization/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Regular expression based text normalization for Chinese - -For simplicity and ease of implementation, text normalization is basically done by rules and dictionaries. Here's an example. diff --git a/examples/tn/.gitignore b/examples/tn/.gitignore new file mode 100644 index 000000000..0f2503386 --- /dev/null +++ b/examples/tn/.gitignore @@ -0,0 +1 @@ +exp diff --git a/examples/tn/README.md b/examples/tn/README.md new file mode 100644 index 000000000..ff7be2934 --- /dev/null +++ b/examples/tn/README.md @@ -0,0 +1,36 @@ +# Regular expression based text normalization for Chinese + +For simplicity and ease of implementation, text normalization is basically done by rules and dictionaries. Here's an example. + +## Run + +``` +. path.sh +bash run.sh +``` + +## Results + +``` +exp/ +`-- normalized.txt + +0 directories, 1 file +``` + +``` +aff31f8aa08e2a7360228c9ce5886b98 exp/normalized.txt +``` + +``` +今天的最低气温达到零下十度. +只要有四分之三十三的人同意,就可以通过决议。 +一九四五年五月二日,苏联士兵在德国国会大厦上升起了胜利旗,象征着攻占柏林并战胜了纳粹德国。 +四月十六日,清晨的战斗以炮击揭幕,数以千计的大炮和喀秋莎火箭炮开始炮轰德军阵地,炮击持续了数天之久。 +如果剩下的百分之三十点六是过去,那么还有百分之六十九点四. +事情发生在二零二零年三月三十一日的上午八点. +警方正在找一支点二二口径的手枪。 +欢迎致电中国联通,北京二零二二年冬奥会官方合作伙伴为您服务 +充值缴费请按一,查询话费及余量请按二,跳过本次提醒请按井号键。 +快速解除流量封顶请按星号键,腾讯王卡产品介绍、使用说明、特权及活动请按九,查询话费、套餐余量、积分及活动返款请按一,手机上网流量开通及取消请按二,查���本机号码及本号所使用套餐请按四,密码修改及重置请按五,紧急开机请按六,挂失请按七,查询充值记录请按八,其它自助服务及工服务请按零 +``` diff --git a/examples/text_normalization/data/sentences.txt b/examples/tn/data/sentences.txt similarity index 100% rename from examples/text_normalization/data/sentences.txt rename to examples/tn/data/sentences.txt diff --git a/examples/text_normalization/local/test_normalization.py b/examples/tn/local/test_normalization.py similarity index 100% rename from examples/text_normalization/local/test_normalization.py rename to examples/tn/local/test_normalization.py diff --git a/examples/text_normalization/path.sh b/examples/tn/path.sh similarity index 100% rename from examples/text_normalization/path.sh rename to examples/tn/path.sh diff --git a/examples/text_normalization/run.sh b/examples/tn/run.sh similarity index 100% rename from examples/text_normalization/run.sh rename to examples/tn/run.sh From 3c16ad788b09e98672a8292c76fede2d68d74bff Mon Sep 17 00:00:00 2001 From: Jackwaterveg <87408988+Jackwaterveg@users.noreply.github.com> Date: Wed, 15 Sep 2021 12:51:29 +0800 Subject: [PATCH 02/33] Update deepspeech_architecture.md --- doc/src/deepspeech_architecture.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/src/deepspeech_architecture.md b/doc/src/deepspeech_architecture.md index dfa60790f..04c7bee79 100644 --- a/doc/src/deepspeech_architecture.md +++ b/doc/src/deepspeech_architecture.md @@ -20,7 +20,7 @@ The arcitecture of the model is shown in Fig.1. ### Data Preparation #### Vocabulary -For English data, the vocabulary dictionary is composed of 26 English characters with " ' ", space, \ and \. The \ represents the blank label in CTC, the \ represents the unknown character and the represents the start and the end characters. For mandarin, the vocabulary dictionary is composed of chinese characters statisticed from the training set and three additional characters are added. The added characters are \, \ and \. For both English and mandarin data, we set the default indexs that \=0, \=1 and \= last index. +For English data, the vocabulary dictionary is composed of 26 English characters with " ' ", space, \ and \. The \ represents the blank label in CTC, the \ represents the unknown character and the \ represents the start and the end characters. For mandarin, the vocabulary dictionary is composed of chinese characters statisticed from the training set and three additional characters are added. The added characters are \, \ and \. For both English and mandarin data, we set the default indexs that \=0, \=1 and \= last index. ``` # The code to build vocabulary cd examples/aishell/s0 @@ -65,17 +65,19 @@ python3 ../../../utils/compute_mean_std.py \ ``` ### Encoder -The Backbone is composed of two 2D convolution subsampling layers and a number of stacked single direction rnn layers. The 2D convolution subsampling layers extract feature represention from the raw audio feature and reduce the length of audio feature at the same time. After passing through the convolution subsampling layers, then the feature represention are input into the stacked rnn layers. For rnn layers, LSTM cell and GRU cell are provided. Adding one fully connected (fc) layer after rnn layer is optional, if the number of rnn layers is less than 5, adding one fc layer after rnn layers is recommand. +The Backbone is composed of two 2D convolution subsampling layers and a number of stacked single direction rnn layers. The 2D convolution subsampling layers extract feature represention from the raw audio feature and reduce the length of audio feature at the same time. After passing through the convolution subsampling layers, then the feature represention are input into the stacked rnn layers. For the stacked rnn layers, LSTM cell and GRU cell are provided to use. Adding one fully connected (fc) layer after the stacked rnn layers is optional. If the number of stacked rnn layers is less than 5, adding one fc layer after stacked rnn layers is recommand. The code of Encoder is in: ``` vi deepspeech/models/ds2_online/deepspeech2.py ``` ### Decoder -To got the character possibilities of each frame, the feature represention of each frame output from the backbone are input into a projection layer which is implemented as a dense layer to do projection. The output dim of the projection layer is same with the vocabulary size. After projection layer, the softmax function is used to make frame-level feature representation be the possibilities of characters. While making model inference, the character possibilities of each frame are input into the CTC decoder to get the final speech recognition results. -The code of Encoder is in: +To got the character possibilities of each frame, the feature represention of each frame output from the encoder are input into a projection layer which is implemented as a dense layer to do feature projection. The output dim of the projection layer is same with the vocabulary size. After projection layer, the softmax function is used to transform the frame-level feature representation be the possibilities of characters. While making model inference, the character possibilities of each frame are input into the CTC decoder to get the final speech recognition results. +The code of Decoder is in: ``` +# The code of constructing the decoder in model vi deepspeech/models/ds2_online/deepspeech2.py +# The code of CTC Decoder vi deepspeech/modules/ctc.py ``` @@ -119,7 +121,7 @@ if [ ${stage} -le 2 ] && [ ${stop_stage} -ge 2 ]; then avg.sh exp/${ckpt}/checkpoints ${avg_num} fi ``` -By using the command above, the training process can be started. There are 5 stages in run.sh, and the first 3 stages are used for training process. The stage 0 is used for data preparation, in which the dataset will be downloaded, and the manifest files of the datasets, vocabulary dictionary and CMVN file will be generated in "./data/". The stage 1 is used for training the model, the log files and model checkpoint is saved in "exp/deepspeech2_online/". The stage 2 is used to generated final model for predicting by averaging the top-k model parameters based on validation loss. +By using the command above, the training process can be started. There are 5 stages in "run.sh", and the first 3 stages are used for training process. The stage 0 is used for data preparation, in which the dataset will be downloaded, and the manifest files of the datasets, vocabulary dictionary and CMVN file will be generated in "./data/". The stage 1 is used for training the model, the log files and model checkpoint is saved in "exp/deepspeech2_online/". The stage 2 is used to generated final model for predicting by averaging the top-k model parameters based on validation loss. ## Testing Process Using the command below, you can test the deepspeech2 online model. @@ -152,7 +154,7 @@ After the training process, we use stage 3,4,5 for testing process. The stage 3 ## Non-Streaming -The deepspeech2 offline model is similarity to the deepspeech2 online model. The main difference between them is the offline model use the bi-directional rnn layers while the online model use the single direction rnn layers and the fc layer is not used. +The deepspeech2 offline model is similarity to the deepspeech2 online model. The main difference between them is the offline model use the stacked bi-directional rnn layers while the online model use the single direction rnn layers and the fc layer is not used. For the stacked bi-directional rnn layers in the offline model, the rnn cell and gru cell are provided to use. The arcitecture of the model is shown in Fig.2.

@@ -162,9 +164,9 @@ The arcitecture of the model is shown in Fig.2. -For data preparation, decoder, the deepspeech2 offline model is same with the deepspeech2 online model. +For data preparation and decoder, the deepspeech2 offline model is same with the deepspeech2 online model. - The code of encoder and decoder for deepspeech2 offline model is in: +The code of encoder and decoder for deepspeech2 offline model is in: ``` vi deepspeech/models/ds2/deepspeech2.py ``` From fbfdf3a95f152ce23528fd81d921d46f69068451 Mon Sep 17 00:00:00 2001 From: Jackwaterveg <87408988+Jackwaterveg@users.noreply.github.com> Date: Wed, 15 Sep 2021 13:01:31 +0800 Subject: [PATCH 03/33] Update deepspeech_architecture.md --- docs/src/deepspeech_architecture.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/src/deepspeech_architecture.md b/docs/src/deepspeech_architecture.md index 6c4951897..f4cfcf9b4 100644 --- a/docs/src/deepspeech_architecture.md +++ b/docs/src/deepspeech_architecture.md @@ -66,6 +66,7 @@ python3 ../../../utils/compute_mean_std.py \ ### Encoder The Backbone is composed of two 2D convolution subsampling layers and a number of stacked single direction rnn layers. The 2D convolution subsampling layers extract feature represention from the raw audio feature and reduce the length of audio feature at the same time. After passing through the convolution subsampling layers, then the feature represention are input into the stacked rnn layers. For the stacked rnn layers, LSTM cell and GRU cell are provided to use. Adding one fully connected (fc) layer after the stacked rnn layers is optional. If the number of stacked rnn layers is less than 5, adding one fc layer after stacked rnn layers is recommand. + The code of Encoder is in: ``` vi deepspeech/models/ds2_online/deepspeech2.py @@ -73,7 +74,8 @@ vi deepspeech/models/ds2_online/deepspeech2.py ### Decoder To got the character possibilities of each frame, the feature represention of each frame output from the encoder are input into a projection layer which is implemented as a dense layer to do feature projection. The output dim of the projection layer is same with the vocabulary size. After projection layer, the softmax function is used to transform the frame-level feature representation be the possibilities of characters. While making model inference, the character possibilities of each frame are input into the CTC decoder to get the final speech recognition results. -The code of Decoder is in: + +The code of the decoder is in: ``` # The code of constructing the decoder in model vi deepspeech/models/ds2_online/deepspeech2.py From 387e1d1177e757b1d25ae40904578ce1e3460168 Mon Sep 17 00:00:00 2001 From: Jackwaterveg <87408988+Jackwaterveg@users.noreply.github.com> Date: Wed, 15 Sep 2021 13:03:02 +0800 Subject: [PATCH 04/33] Update deepspeech_architecture.md --- docs/src/deepspeech_architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/deepspeech_architecture.md b/docs/src/deepspeech_architecture.md index f4cfcf9b4..580b13882 100644 --- a/docs/src/deepspeech_architecture.md +++ b/docs/src/deepspeech_architecture.md @@ -65,7 +65,7 @@ python3 ../../../utils/compute_mean_std.py \ ``` ### Encoder -The Backbone is composed of two 2D convolution subsampling layers and a number of stacked single direction rnn layers. The 2D convolution subsampling layers extract feature represention from the raw audio feature and reduce the length of audio feature at the same time. After passing through the convolution subsampling layers, then the feature represention are input into the stacked rnn layers. For the stacked rnn layers, LSTM cell and GRU cell are provided to use. Adding one fully connected (fc) layer after the stacked rnn layers is optional. If the number of stacked rnn layers is less than 5, adding one fc layer after stacked rnn layers is recommand. +The encoder is composed of two 2D convolution subsampling layers and a number of stacked single direction rnn layers. The 2D convolution subsampling layers extract feature represention from the raw audio feature and reduce the length of audio feature at the same time. After passing through the convolution subsampling layers, then the feature represention are input into the stacked rnn layers. For the stacked rnn layers, LSTM cell and GRU cell are provided to use. Adding one fully connected (fc) layer after the stacked rnn layers is optional. If the number of stacked rnn layers is less than 5, adding one fc layer after stacked rnn layers is recommand. The code of Encoder is in: ``` From 027e90656e3f302d476a659accfe061ea36ad256 Mon Sep 17 00:00:00 2001 From: Jackwaterveg <87408988+Jackwaterveg@users.noreply.github.com> Date: Wed, 15 Sep 2021 13:14:12 +0800 Subject: [PATCH 05/33] Emphasis the setup stage in install.sh --- docs/src/install.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/install.md b/docs/src/install.md index 01049a2fc..79460737b 100644 --- a/docs/src/install.md +++ b/docs/src/install.md @@ -6,13 +6,14 @@ To avoid the trouble of environment setup, [running in Docker container](#runnin - Python >= 3.7 - PaddlePaddle 2.0.0 or later (please refer to the [Installation Guide](https://www.paddlepaddle.org.cn/documentation/docs/en/beginners_guide/index_en.html)) -## Setup +## Setup (Important) - Make sure these libraries or tools installed: `pkg-config`, `flac`, `ogg`, `vorbis`, `boost`, `sox, and `swig`, e.g. installing them via `apt-get`: ```bash sudo apt-get install -y sox pkg-config libflac-dev libogg-dev libvorbis-dev libboost-dev swig python3-dev ``` +The version of `swig` should >= 3.0 or, installing them via `yum`: From 8d44aa481323291fd78f951a62d83c15eff9d31f Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Wed, 15 Sep 2021 06:08:14 +0000 Subject: [PATCH 06/33] do not set seed since break model covergence, aishell s0 seed 10086 test ok --- examples/aishell/s0/local/train.sh | 1 + examples/aishell/s1/local/train.sh | 5 ++-- examples/callcenter/s1/local/train.sh | 5 ++-- examples/librispeech/s0/local/train.sh | 3 ++- examples/librispeech/s1/local/train.sh | 5 ++-- examples/librispeech/s2/local/train.sh | 3 ++- examples/ted_en_zh/t0/local/train.sh | 5 ++-- examples/timit/s1/local/train.sh | 3 ++- examples/tiny/s0/local/train.sh | 3 ++- examples/tiny/s0/local/tune.sh | 33 -------------------------- examples/tiny/s1/local/train.sh | 3 ++- 11 files changed, 23 insertions(+), 46 deletions(-) delete mode 100755 examples/tiny/s0/local/tune.sh diff --git a/examples/aishell/s0/local/train.sh b/examples/aishell/s0/local/train.sh index 85d1d42c3..668ad0ead 100755 --- a/examples/aishell/s0/local/train.sh +++ b/examples/aishell/s0/local/train.sh @@ -19,6 +19,7 @@ fi mkdir -p exp +# seed may break model convergence seed=10086 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True diff --git a/examples/aishell/s1/local/train.sh b/examples/aishell/s1/local/train.sh index 2861e11ec..f905b766e 100755 --- a/examples/aishell/s1/local/train.sh +++ b/examples/aishell/s1/local/train.sh @@ -19,8 +19,9 @@ echo "using ${device}..." mkdir -p exp -seed=10086 -if [ ${seed} != 0]; then +# seed may break model convergence +seed=0 +if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi diff --git a/examples/callcenter/s1/local/train.sh b/examples/callcenter/s1/local/train.sh index 6e63df83a..d5dc15b03 100755 --- a/examples/callcenter/s1/local/train.sh +++ b/examples/callcenter/s1/local/train.sh @@ -19,8 +19,9 @@ echo "using ${device}..." mkdir -p exp -seed=10086 -if [ ${seed} != 0]; then +# seed may break model convergence +seed=0 +if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi diff --git a/examples/librispeech/s0/local/train.sh b/examples/librispeech/s0/local/train.sh index c95659acf..6aee372a4 100755 --- a/examples/librispeech/s0/local/train.sh +++ b/examples/librispeech/s0/local/train.sh @@ -20,7 +20,8 @@ echo "using ${device}..." mkdir -p exp -seed=10086 +# seed may break model convergence +seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi diff --git a/examples/librispeech/s1/local/train.sh b/examples/librispeech/s1/local/train.sh index 17a9e28df..f905b766e 100755 --- a/examples/librispeech/s1/local/train.sh +++ b/examples/librispeech/s1/local/train.sh @@ -19,7 +19,8 @@ echo "using ${device}..." mkdir -p exp -seed=10086 +# seed may break model convergence +seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi @@ -31,7 +32,7 @@ python3 -u ${BIN_DIR}/train.py \ --output exp/${ckpt_name} \ --seed ${seed} -if [ ${seed} != 0]; then +if [ ${seed} != 0 ]; then unset FLAGS_cudnn_deterministic fi diff --git a/examples/librispeech/s2/local/train.sh b/examples/librispeech/s2/local/train.sh index a75e2bb26..66754201f 100755 --- a/examples/librispeech/s2/local/train.sh +++ b/examples/librispeech/s2/local/train.sh @@ -19,7 +19,8 @@ echo "using ${device}..." mkdir -p exp -seed=10086 +# seed may break model convergence +seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi diff --git a/examples/ted_en_zh/t0/local/train.sh b/examples/ted_en_zh/t0/local/train.sh index 928356f96..f905b766e 100755 --- a/examples/ted_en_zh/t0/local/train.sh +++ b/examples/ted_en_zh/t0/local/train.sh @@ -19,7 +19,8 @@ echo "using ${device}..." mkdir -p exp -seed=10086 +# seed may break model convergence +seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi @@ -31,7 +32,7 @@ python3 -u ${BIN_DIR}/train.py \ --output exp/${ckpt_name} \ --seed ${seed} -if [ ${seed} != 0 ]; then +if [ ${seed} != 0 ]; then unset FLAGS_cudnn_deterministic fi diff --git a/examples/timit/s1/local/train.sh b/examples/timit/s1/local/train.sh index 3e2e4522d..180d8b5a7 100755 --- a/examples/timit/s1/local/train.sh +++ b/examples/timit/s1/local/train.sh @@ -19,7 +19,8 @@ echo "using ${device}..." mkdir -p exp -seed=10086 +# seed may break model convergence +seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi diff --git a/examples/tiny/s0/local/train.sh b/examples/tiny/s0/local/train.sh index bf4766ee3..ea29b7fcf 100755 --- a/examples/tiny/s0/local/train.sh +++ b/examples/tiny/s0/local/train.sh @@ -19,7 +19,8 @@ fi mkdir -p exp -seed=10086 +# seed may break model convergence +seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi diff --git a/examples/tiny/s0/local/tune.sh b/examples/tiny/s0/local/tune.sh deleted file mode 100755 index c344e77e5..000000000 --- a/examples/tiny/s0/local/tune.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -if [ $# != 1 ];then - echo "usage: tune ckpt_path" - exit 1 -fi - -# grid-search for hyper-parameters in language model -python3 -u ${BIN_DIR}/tune.py \ ---device 'gpu' \ ---nproc 1 \ ---config conf/deepspeech2.yaml \ ---num_batches=-1 \ ---batch_size=128 \ ---beam_size=500 \ ---num_proc_bsearch=12 \ ---num_alphas=45 \ ---num_betas=8 \ ---alpha_from=1.0 \ ---alpha_to=3.2 \ ---beta_from=0.1 \ ---beta_to=0.45 \ ---cutoff_prob=1.0 \ ---cutoff_top_n=40 \ ---checkpoint_path ${1} - -if [ $? -ne 0 ]; then - echo "Failed in tuning!" - exit 1 -fi - - -exit 0 diff --git a/examples/tiny/s1/local/train.sh b/examples/tiny/s1/local/train.sh index 48968f63c..374608fd1 100755 --- a/examples/tiny/s1/local/train.sh +++ b/examples/tiny/s1/local/train.sh @@ -18,7 +18,8 @@ fi mkdir -p exp -seed=10086 +# seed may break model convergence +seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True fi From fba22201aa00be55b5342c2a4001a821ab5cb6a2 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Wed, 15 Sep 2021 09:11:32 +0000 Subject: [PATCH 07/33] add op profiling --- deepspeech/exps/u2/bin/train.py | 1 + deepspeech/exps/u2/model.py | 1 + deepspeech/exps/u2_kaldi/model.py | 1 + deepspeech/exps/u2_st/model.py | 1 + deepspeech/training/cli.py | 5 + deepspeech/training/trainer.py | 5 + deepspeech/utils/profiler.py | 116 ++++++++++++++++++ examples/aishell/s1/local/train.sh | 37 +++--- examples/librispeech/s0/conf/deepspeech2.yaml | 4 +- examples/tiny/s0/local/train.sh | 32 +++-- 10 files changed, 174 insertions(+), 29 deletions(-) create mode 100644 deepspeech/utils/profiler.py diff --git a/deepspeech/exps/u2/bin/train.py b/deepspeech/exps/u2/bin/train.py index fef615ce3..b664401a2 100644 --- a/deepspeech/exps/u2/bin/train.py +++ b/deepspeech/exps/u2/bin/train.py @@ -21,6 +21,7 @@ from deepspeech.exps.u2.config import get_cfg_defaults from deepspeech.exps.u2.model import U2Trainer as Trainer from deepspeech.training.cli import default_argument_parser from deepspeech.utils.utility import print_arguments + # from deepspeech.exps.u2.trainer import U2Trainer as Trainer diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 2b6e24330..67b666ed0 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -204,6 +204,7 @@ class U2Trainer(Trainer): msg += "lr: {:>.8f}, ".format(self.lr_scheduler()) msg += "data time: {:>.3f}s, ".format(dataload_time) self.train_batch(batch_index, batch, msg) + self.after_train_batch() data_start_time = time.time() except Exception as e: logger.error(e) diff --git a/deepspeech/exps/u2_kaldi/model.py b/deepspeech/exps/u2_kaldi/model.py index 095dfe34d..3d15e0259 100644 --- a/deepspeech/exps/u2_kaldi/model.py +++ b/deepspeech/exps/u2_kaldi/model.py @@ -205,6 +205,7 @@ class U2Trainer(Trainer): msg += "lr: {:>.8f}, ".format(self.lr_scheduler()) msg += "data time: {:>.3f}s, ".format(dataload_time) self.train_batch(batch_index, batch, msg) + self.after_train_batch() data_start_time = time.time() except Exception as e: logger.error(e) diff --git a/deepspeech/exps/u2_st/model.py b/deepspeech/exps/u2_st/model.py index 8dca16540..91a81503f 100644 --- a/deepspeech/exps/u2_st/model.py +++ b/deepspeech/exps/u2_st/model.py @@ -222,6 +222,7 @@ class U2STTrainer(Trainer): msg += "lr: {:>.8f}, ".format(self.lr_scheduler()) msg += "data time: {:>.3f}s, ".format(dataload_time) self.train_batch(batch_index, batch, msg) + self.after_train_batch() data_start_time = time.time() except Exception as e: logger.error(e) diff --git a/deepspeech/training/cli.py b/deepspeech/training/cli.py index 7f4bb8048..1477bdfe0 100644 --- a/deepspeech/training/cli.py +++ b/deepspeech/training/cli.py @@ -63,8 +63,13 @@ def default_argument_parser(): parser.add_argument("--opts", type=str, default=[], nargs='+', help="options to overwrite --config file and the default config, passing in KEY VALUE pairs") + # random seed parser.add_argument("--seed", type=int, default=None, help="seed to use for paddle, np and random. None or 0 for random, else set seed.") + + # profiler + parser.add_argument('--profiler_options', type=str, default=None, + help='The option of profiler, which should be in format \"key1=value1;key2=value2;key3=value3\".') # yapd: enable return parser diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index 7959b41b8..bdb68310a 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -20,6 +20,7 @@ from tensorboardX import SummaryWriter from deepspeech.training.timer import Timer from deepspeech.utils import mp_tools +from deepspeech.utils import profiler from deepspeech.utils.checkpoint import Checkpoint from deepspeech.utils.log import Log from deepspeech.utils.utility import seed_all @@ -183,6 +184,9 @@ class Trainer(): if isinstance(batch_sampler, paddle.io.DistributedBatchSampler): batch_sampler.set_epoch(self.epoch) + def after_train_batch(self): + profiler.add_profiler_step(self.args.profiler_options) + def train(self): """The training process control by epoch.""" from_scratch = self.resume_or_scratch() @@ -209,6 +213,7 @@ class Trainer(): msg += "lr: {:>.8f}, ".format(self.lr_scheduler()) msg += "data time: {:>.3f}s, ".format(dataload_time) self.train_batch(batch_index, batch, msg) + self.after_train_batch() data_start_time = time.time() except Exception as e: logger.error(e) diff --git a/deepspeech/utils/profiler.py b/deepspeech/utils/profiler.py new file mode 100644 index 000000000..5b8389be8 --- /dev/null +++ b/deepspeech/utils/profiler.py @@ -0,0 +1,116 @@ +# copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve. +# +# 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 + +from deepspeech.utils.log import Log + +logger = Log(__name__).getlog() + +# A global variable to record the number of calling times for profiler +# functions. It is used to specify the tracing range of training steps. +_profiler_step_id = 0 + +# A global variable to avoid parsing from string every time. +_profiler_options = None + + +class ProfilerOptions(object): + ''' + Use a string to initialize a ProfilerOptions. + The string should be in the format: "key1=value1;key2=value;key3=value3". + For example: + "profile_path=model.profile" + "batch_range=[50, 60]; profile_path=model.profile" + "batch_range=[50, 60]; tracer_option=OpDetail; profile_path=model.profile" + ProfilerOptions supports following key-value pair: + batch_range - a integer list, e.g. [100, 110]. + state - a string, the optional values are 'CPU', 'GPU' or 'All'. + sorted_key - a string, the optional values are 'calls', 'total', + 'max', 'min' or 'ave. + tracer_option - a string, the optional values are 'Default', 'OpDetail', + 'AllOpDetail'. + profile_path - a string, the path to save the serialized profile data, + which can be used to generate a timeline. + exit_on_finished - a boolean. + ''' + + def __init__(self, options_str): + assert isinstance(options_str, str) + + self._options = { + 'batch_range': [10, 20], + 'state': 'All', + 'sorted_key': 'total', + 'tracer_option': 'Default', + 'profile_path': '/tmp/profile', + 'exit_on_finished': True + } + self._parse_from_string(options_str) + + def _parse_from_string(self, options_str): + for kv in options_str.replace(' ', '').split(';'): + key, value = kv.split('=') + if key == 'batch_range': + value_list = value.replace('[', '').replace(']', '').split(',') + value_list = list(map(int, value_list)) + if len(value_list) >= 2 and value_list[0] >= 0 and value_list[ + 1] > value_list[0]: + self._options[key] = value_list + elif key == 'exit_on_finished': + self._options[key] = value.lower() in ("yes", "true", "t", "1") + elif key in [ + 'state', 'sorted_key', 'tracer_option', 'profile_path' + ]: + self._options[key] = value + + def __getitem__(self, name): + if self._options.get(name, None) is None: + raise ValueError( + "ProfilerOptions does not have an option named %s." % name) + return self._options[name] + + +def add_profiler_step(options_str=None): + ''' + Enable the operator-level timing using PaddlePaddle's profiler. + The profiler uses a independent variable to count the profiler steps. + One call of this function is treated as a profiler step. + + Args: + profiler_options - a string to initialize the ProfilerOptions. + Default is None, and the profiler is disabled. + ''' + if options_str is None: + return + + global _profiler_step_id + global _profiler_options + + if _profiler_options is None: + _profiler_options = ProfilerOptions(options_str) + logger.info(f"{options_str}") + logger.info(f"{_profiler_options._options}") + + if _profiler_step_id == _profiler_options['batch_range'][0]: + paddle.utils.profiler.start_profiler(_profiler_options['state'], + _profiler_options['tracer_option']) + elif _profiler_step_id == _profiler_options['batch_range'][1]: + paddle.utils.profiler.stop_profiler(_profiler_options['sorted_key'], + _profiler_options['profile_path']) + if _profiler_options['exit_on_finished']: + sys.exit(0) + + _profiler_step_id += 1 diff --git a/examples/aishell/s1/local/train.sh b/examples/aishell/s1/local/train.sh index f905b766e..e065ad6a8 100755 --- a/examples/aishell/s1/local/train.sh +++ b/examples/aishell/s1/local/train.sh @@ -1,38 +1,45 @@ #!/bin/bash -if [ $# != 2 ];then - echo "usage: CUDA_VISIBLE_DEVICES=0 ${0} config_path ckpt_name" - exit -1 -fi + +profiler_options= + +# seed may break model convergence +seed=0 + +source ${MAIN_ROOT}/utils/parse_options.sh || exit 1; ngpu=$(echo $CUDA_VISIBLE_DEVICES | awk -F "," '{print NF}') echo "using $ngpu gpus..." -config_path=$1 -ckpt_name=$2 - device=gpu if [ ${ngpu} == 0 ];then device=cpu fi -echo "using ${device}..." - -mkdir -p exp -# seed may break model convergence -seed=0 -if [ ${seed} != 0 ]; then +if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True + echo "using seed $seed & FLAGS_cudnn_deterministic=True ..." fi +if [ $# != 2 ];then + echo "usage: CUDA_VISIBLE_DEVICES=0 ${0} config_path ckpt_name" + exit -1 +fi + +config_path=$1 +ckpt_name=$2 + +mkdir -p exp + python3 -u ${BIN_DIR}/train.py \ --device ${device} \ --nproc ${ngpu} \ --config ${config_path} \ --output exp/${ckpt_name} \ +--profiler_options ${profiler_options} \ --seed ${seed} -if [ ${seed} != 0 ]; then +if [ ${seed} != 0 ]; then unset FLAGS_cudnn_deterministic fi @@ -41,4 +48,4 @@ if [ $? -ne 0 ]; then exit 1 fi -exit 0 +exit 0 \ No newline at end of file diff --git a/examples/librispeech/s0/conf/deepspeech2.yaml b/examples/librispeech/s0/conf/deepspeech2.yaml index d5b1ed919..3f1a376f1 100644 --- a/examples/librispeech/s0/conf/deepspeech2.yaml +++ b/examples/librispeech/s0/conf/deepspeech2.yaml @@ -11,7 +11,7 @@ data: max_output_input_ratio: .inf collator: - batch_size: 15 + batch_size: 20 mean_std_filepath: data/mean_std.json unit_type: char vocab_filepath: data/vocab.txt @@ -45,7 +45,7 @@ model: training: n_epoch: 50 - accum_grad: 4 + accum_grad: 1 lr: 1e-3 lr_decay: 0.83 weight_decay: 1e-06 diff --git a/examples/tiny/s0/local/train.sh b/examples/tiny/s0/local/train.sh index ea29b7fcf..a657ce345 100755 --- a/examples/tiny/s0/local/train.sh +++ b/examples/tiny/s0/local/train.sh @@ -1,36 +1,44 @@ #!/bin/bash -if [ $# != 3 ];then - echo "usage: CUDA_VISIBLE_DEVICES=0 ${0} config_path ckpt_name model_type" - exit -1 -fi +profiler_options= + +# seed may break model convergence +seed=0 + +source ${MAIN_ROOT}/utils/parse_options.sh || exit 1; ngpu=$(echo $CUDA_VISIBLE_DEVICES | awk -F "," '{print NF}') echo "using $ngpu gpus..." -config_path=$1 -ckpt_name=$2 -model_type=$3 - device=gpu if [ ${ngpu} == 0 ];then device=cpu fi -mkdir -p exp - -# seed may break model convergence -seed=0 if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True + echo "using seed $seed & FLAGS_cudnn_deterministic=True ..." +fi + + +if [ $# != 3 ];then + echo "usage: CUDA_VISIBLE_DEVICES=0 ${0} config_path ckpt_name model_type" + exit -1 fi +config_path=$1 +ckpt_name=$2 +model_type=$3 + +mkdir -p exp + python3 -u ${BIN_DIR}/train.py \ --device ${device} \ --nproc ${ngpu} \ --config ${config_path} \ --output exp/${ckpt_name} \ --model_type ${model_type} \ +--profiler_options ${profiler_options} \ --seed ${seed} if [ ${seed} != 0 ]; then From aee7acb090afffc6fec049c724add9527ea6eab4 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Wed, 15 Sep 2021 11:03:18 +0000 Subject: [PATCH 08/33] add benmark scripts --- tests/benchmark/.gitignore | 2 + tests/benchmark/README.md | 12 +++ tests/benchmark/run_all.sh | 33 ++++++ tests/benchmark/run_benchmark.sh | 54 ++++++++++ utils/pd_env_collect.sh | 167 +++++++++++++++++++++++++++++++ 5 files changed, 268 insertions(+) create mode 100644 tests/benchmark/.gitignore create mode 100644 tests/benchmark/README.md create mode 100644 tests/benchmark/run_all.sh create mode 100644 tests/benchmark/run_benchmark.sh create mode 100644 utils/pd_env_collect.sh diff --git a/tests/benchmark/.gitignore b/tests/benchmark/.gitignore new file mode 100644 index 000000000..7d166b066 --- /dev/null +++ b/tests/benchmark/.gitignore @@ -0,0 +1,2 @@ +old-pd_env.txt +pd_env.txt diff --git a/tests/benchmark/README.md b/tests/benchmark/README.md new file mode 100644 index 000000000..8ec43f89e --- /dev/null +++ b/tests/benchmark/README.md @@ -0,0 +1,12 @@ +# Benchmark Test + +## Data + +* Aishell + +## Docker + +``` +registry.baidubce.com/paddlepaddle/paddle 2.1.1-gpu-cuda10.2-cudnn7 59d5ec1de486 +``` + diff --git a/tests/benchmark/run_all.sh b/tests/benchmark/run_all.sh new file mode 100644 index 000000000..7564174b4 --- /dev/null +++ b/tests/benchmark/run_all.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# collect env info +bash ../../utils/pd_env_collect.sh + + + +# 提供可稳定复现性能的脚本,默认在标准docker环境内py37执行: paddlepaddle/paddle:latest-gpu-cuda10.1-cudnn7 paddle=2.1.2 py=37 +# 执行目录:需说明 +cd ** +# 1 安装该模型需要的依赖 (如需开启优化策略请注明) +pip install ... +# 2 拷贝该模型需要数据、预训练模型 +# 3 批量运行(如不方便批量,1,2需放到单个模型中) + +model_mode_list=(MobileNetv1 MobileNetv2) +fp_item_list=(fp32 fp16) +bs_item=(32 64 96) +for model_mode in ${model_mode_list[@]}; do + for fp_item in ${fp_item_list[@]}; do + for bs_item in ${bs_list[@]} + do + echo "index is speed, 1gpus, begin, ${model_name}" + run_mode=sp + CUDA_VISIBLE_DEVICES=0 bash run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} # (5min) + sleep 60 + echo "index is speed, 8gpus, run_mode is multi_process, begin, ${model_name}" + run_mode=mp + CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 bash run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} + sleep 60 + done + done +done diff --git a/tests/benchmark/run_benchmark.sh b/tests/benchmark/run_benchmark.sh new file mode 100644 index 000000000..2b9cf70fd --- /dev/null +++ b/tests/benchmark/run_benchmark.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -xe +# 运行示例:CUDA_VISIBLE_DEVICES=0 bash run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} +# 参数说明 +function _set_params(){ + run_mode=${1:-"sp"} # 单卡sp|多卡mp + batch_size=${2:-"64"} + fp_item=${3:-"fp32"} # fp32|fp16 + max_iter=${4:-"500"} # 可选,如果需要修改代码提前中断 + model_name=${5:-"model_name"} + run_log_path=${TRAIN_LOG_DIR:-$(pwd)} # TRAIN_LOG_DIR 后续QA设置该参数 + +# 以下不用修改 + device=${CUDA_VISIBLE_DEVICES//,/ } + arr=(${device}) + num_gpu_devices=${#arr[*]} + log_file=${run_log_path}/${model_name}_${run_mode}_bs${batch_size}_${fp_item}_${num_gpu_devices} +} +function _train(){ + echo "Train on ${num_gpu_devices} GPUs" + echo "current CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES, gpus=$num_gpu_devices, batch_size=$batch_size" + + train_cmd="--model_name=${model_name} + --batch_size=${batch_size} + --fp=${fp_item} \ + --max_iter=${max_iter} " + case ${run_mode} in + sp) train_cmd="python -u tools/train.py "${train_cmd}" ;; + mp) + train_cmd="python -m paddle.distributed.launch --log_dir=./mylog --gpus=$CUDA_VISIBLE_DEVICES tools/train.py "${train_cmd}" + log_parse_file="mylog/workerlog.0" ;; + *) echo "choose run_mode(sp or mp)"; exit 1; + esac +# 以下不用修改 + timeout 15m ${train_cmd} > ${log_file} 2>&1 + if [ $? -ne 0 ];then + echo -e "${model_name}, FAIL" + export job_fail_flag=1 + else + echo -e "${model_name}, SUCCESS" + export job_fail_flag=0 + fi + kill -9 `ps -ef|grep 'python'|awk '{print $2}'` + + if [ $run_mode = "mp" -a -d mylog ]; then + rm ${log_file} + cp mylog/workerlog.0 ${log_file} + fi +} + +_set_params $@ +_train + diff --git a/utils/pd_env_collect.sh b/utils/pd_env_collect.sh new file mode 100644 index 000000000..64ff8886c --- /dev/null +++ b/utils/pd_env_collect.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env bash + +unset GREP_OPTIONS + +set -u # Check for undefined variables + +die() { + # Print a message and exit with code 1. + # + # Usage: die + # e.g., die "Something bad happened." + + echo $@ + exit 1 +} + +echo "Collecting system information..." + +OUTPUT_FILE=pd_env.txt +python_bin_path=$(which python || which python3 || die "Cannot find Python binary") + +{ +echo +echo '== check python ===================================================' +} >> ${OUTPUT_FILE} + +cat < /tmp/check_python.py +import platform +print("""python version: %s +python branch: %s +python build version: %s +python compiler version: %s +python implementation: %s +""" % ( +platform.python_version(), +platform.python_branch(), +platform.python_build(), +platform.python_compiler(), +platform.python_implementation(), +)) +EOF +${python_bin_path} /tmp/check_python.py 2>&1 >> ${OUTPUT_FILE} + +{ +echo +echo '== check os platform ===============================================' +} >> ${OUTPUT_FILE} + +cat < /tmp/check_os.py +import platform +print("""os: %s +os kernel version: %s +os release version: %s +os platform: %s +linux distribution: %s +linux os distribution: %s +mac version: %s +uname: %s +architecture: %s +machine: %s +""" % ( +platform.system(), +platform.version(), +platform.release(), +platform.platform(), +platform.linux_distribution(), +platform.dist(), +platform.mac_ver(), +platform.uname(), +platform.architecture(), +platform.machine(), +)) +EOF +${python_bin_path} /tmp/check_os.py 2>&1 >> ${OUTPUT_FILE} + +{ + echo + echo '== are we in docker =============================================' + num=`cat /proc/1/cgroup | grep docker | wc -l`; + if [ $num -ge 1 ]; then + echo "Yes" + else + echo "No" + fi + + echo + echo '== compiler =====================================================' + c++ --version 2>&1 + + echo + echo '== check pips ===================================================' + pip list 2>&1 | grep "proto\|numpy\|paddlepaddle" + + + echo + echo '== check for virtualenv =========================================' + ${python_bin_path} -c "import sys;print(hasattr(sys, \"real_prefix\"))" + + echo + echo '== paddlepaddle import ============================================' +} >> ${OUTPUT_FILE} + +cat < /tmp/check_pd.py +import paddle as pd; +pd.set_device('cpu') +print("pd.version.full_version = %s" % pd.version.full_version) +print("pd.version.commit = %s" % pd.version.commit) +print("pd.__version__ = %s" % pd.__version__) +print("Sanity check: %r" % pd.zeros([1,2,3])[:1]) +EOF +${python_bin_path} /tmp/check_pd.py 2>&1 >> ${OUTPUT_FILE} + +LD_DEBUG=libs ${python_bin_path} -c "import paddle" 2>>${OUTPUT_FILE} > /tmp/loadedlibs + +{ + grep libcudnn.so /tmp/loadedlibs + echo + echo '== env ==========================================================' + if [ -z ${LD_LIBRARY_PATH+x} ]; then + echo "LD_LIBRARY_PATH is unset"; + else + echo LD_LIBRARY_PATH ${LD_LIBRARY_PATH} ; + fi + if [ -z ${DYLD_LIBRARY_PATH+x} ]; then + echo "DYLD_LIBRARY_PATH is unset"; + else + echo DYLD_LIBRARY_PATH ${DYLD_LIBRARY_PATH} ; + fi + + + echo + echo '== nvidia-smi ===================================================' + nvidia-smi 2>&1 + + echo + echo '== cuda libs ===================================================' +} >> ${OUTPUT_FILE} + +find /usr/local -type f -name 'libcudart*' 2>/dev/null | grep cuda | grep -v "\\.cache" >> ${OUTPUT_FILE} +find /usr/local -type f -name 'libudnn*' 2>/dev/null | grep cuda | grep -v "\\.cache" >> ${OUTPUT_FILE} + +{ + echo + echo '== paddlepaddle installed from info ==================' + pip show paddlepaddle-gpu + + echo + echo '== python version ==============================================' + echo '(major, minor, micro, releaselevel, serial)' + python -c 'import sys; print(sys.version_info[:])' + + echo + echo '== bazel version ===============================================' + bazel version + echo '== cmake version ===============================================' + cmake --version +} >> ${OUTPUT_FILE} + +# Remove any words with google. +mv $OUTPUT_FILE old-$OUTPUT_FILE +grep -v -i google old-${OUTPUT_FILE} > $OUTPUT_FILE + +echo "Wrote environment to ${OUTPUT_FILE}. You can review the contents of that file." +echo "and use it to populate the fields in the github issue template." +echo +echo "cat ${OUTPUT_FILE}" +echo From b6d0f2fab8df3d70ef643242f3cd4bcc40b64092 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Wed, 15 Sep 2021 11:26:07 +0000 Subject: [PATCH 09/33] fix profiler --- deepspeech/training/trainer.py | 3 ++- deepspeech/utils/profiler.py | 3 +++ examples/tiny/s0/conf/deepspeech2.yaml | 2 +- examples/tiny/s0/local/train.sh | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index bdb68310a..b31ddcad6 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -185,7 +185,8 @@ class Trainer(): batch_sampler.set_epoch(self.epoch) def after_train_batch(self): - profiler.add_profiler_step(self.args.profiler_options) + if self.args.profiler_options: + profiler.add_profiler_step(self.args.profiler_options) def train(self): """The training process control by epoch.""" diff --git a/deepspeech/utils/profiler.py b/deepspeech/utils/profiler.py index 5b8389be8..357840a62 100644 --- a/deepspeech/utils/profiler.py +++ b/deepspeech/utils/profiler.py @@ -61,6 +61,9 @@ class ProfilerOptions(object): self._parse_from_string(options_str) def _parse_from_string(self, options_str): + if not options_str: + return + for kv in options_str.replace(' ', '').split(';'): key, value = kv.split('=') if key == 'batch_range': diff --git a/examples/tiny/s0/conf/deepspeech2.yaml b/examples/tiny/s0/conf/deepspeech2.yaml index 64598b4be..408996557 100644 --- a/examples/tiny/s0/conf/deepspeech2.yaml +++ b/examples/tiny/s0/conf/deepspeech2.yaml @@ -48,7 +48,7 @@ training: n_epoch: 10 accum_grad: 1 lr: 1e-5 - lr_decay: 1.0 + lr_decay: 0.8 weight_decay: 1e-06 global_grad_clip: 5.0 log_interval: 1 diff --git a/examples/tiny/s0/local/train.sh b/examples/tiny/s0/local/train.sh index a657ce345..f96508b4f 100755 --- a/examples/tiny/s0/local/train.sh +++ b/examples/tiny/s0/local/train.sh @@ -38,7 +38,7 @@ python3 -u ${BIN_DIR}/train.py \ --config ${config_path} \ --output exp/${ckpt_name} \ --model_type ${model_type} \ ---profiler_options ${profiler_options} \ +--profiler_options "${profiler_options}" \ --seed ${seed} if [ ${seed} != 0 ]; then From 086b96dddf310c37abec9867193ed0c58d2a1497 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Wed, 15 Sep 2021 11:36:35 +0000 Subject: [PATCH 10/33] lr and opt param will restore from ckpt, so we do not set lr manully --- deepspeech/exps/u2/model.py | 5 +++-- deepspeech/training/trainer.py | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 67b666ed0..1328a1cb7 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -182,9 +182,10 @@ class U2Trainer(Trainer): from_scratch = self.resume_or_scratch() if from_scratch: # save init model, i.e. 0 epoch - self.save(tag='init') + self.save(tag='init', infos=None) - self.lr_scheduler.step(self.iteration) + # lr will resotre from optimizer ckpt + # self.lr_scheduler.step(self.iteration) if self.parallel and hasattr(self.train_loader, 'batch_sampler'): self.train_loader.batch_sampler.set_epoch(self.epoch) diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index b31ddcad6..6587f1290 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -194,7 +194,9 @@ class Trainer(): if from_scratch: # save init model, i.e. 0 epoch self.save(tag='init', infos=None) - self.lr_scheduler.step(self.epoch) + + # lr will resotre from optimizer ckpt + # self.lr_scheduler.step(self.epoch) if self.parallel and hasattr(self.train_loader, "batch_sampler"): self.train_loader.batch_sampler.set_epoch(self.epoch) From 9d10da0da76fb2ac1dcf3e4ae5103550991715c1 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Wed, 15 Sep 2021 11:42:07 +0000 Subject: [PATCH 11/33] format --- deepspeech/utils/profiler.py | 2 +- tests/benchmark/README.md | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/deepspeech/utils/profiler.py b/deepspeech/utils/profiler.py index 357840a62..83b003cad 100644 --- a/deepspeech/utils/profiler.py +++ b/deepspeech/utils/profiler.py @@ -63,7 +63,7 @@ class ProfilerOptions(object): def _parse_from_string(self, options_str): if not options_str: return - + for kv in options_str.replace(' ', '').split(';'): key, value = kv.split('=') if key == 'batch_range': diff --git a/tests/benchmark/README.md b/tests/benchmark/README.md index 8ec43f89e..d21999ab3 100644 --- a/tests/benchmark/README.md +++ b/tests/benchmark/README.md @@ -4,9 +4,8 @@ * Aishell -## Docker +## Docker ``` registry.baidubce.com/paddlepaddle/paddle 2.1.1-gpu-cuda10.2-cudnn7 59d5ec1de486 ``` - From 1721626246f648e263fd8d629a36b91369cdf15a Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Thu, 16 Sep 2021 05:59:16 +0000 Subject: [PATCH 12/33] run_all with aishell/s1 --- tests/benchmark/run_all.sh | 27 +++++++++++++++++++-------- tests/benchmark/run_benchmark.sh | 2 ++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/benchmark/run_all.sh b/tests/benchmark/run_all.sh index 7564174b4..7aa11d0f2 100644 --- a/tests/benchmark/run_all.sh +++ b/tests/benchmark/run_all.sh @@ -1,20 +1,29 @@ #!/bin/bash -# collect env info -bash ../../utils/pd_env_collect.sh - +ROOT_DIR=../../ +# 提供可稳定复现性能的脚本,默认在标准docker环境内py37执行: +# collect env info +bash ${ROOT_DIR}/utils/pd_env_collect.sh +cat pd_env.txt -# 提供可稳定复现性能的脚本,默认在标准docker环境内py37执行: paddlepaddle/paddle:latest-gpu-cuda10.1-cudnn7 paddle=2.1.2 py=37 # 执行目录:需说明 -cd ** +pushd ${ROOT_DIR}/examples/aishell/s1 + # 1 安装该模型需要的依赖 (如需开启优化策略请注明) -pip install ... +pushd ${ROOT_DIR}/tools; make; popd +source ${ROOT_DIR}/tools/venv/bin/activate +pushd ${ROOT_DIR}; bash setup.sh; popd + + # 2 拷贝该模型需要数据、预训练模型 +mkdir -p exp/log +loca/data.sh &> exp/log/data.log + # 3 批量运行(如不方便批量,1,2需放到单个模型中) -model_mode_list=(MobileNetv1 MobileNetv2) -fp_item_list=(fp32 fp16) +model_mode_list=(conformer) +fp_item_list=(fp32) bs_item=(32 64 96) for model_mode in ${model_mode_list[@]}; do for fp_item in ${fp_item_list[@]}; do @@ -31,3 +40,5 @@ for model_mode in ${model_mode_list[@]}; do done done done + +popd # aishell/s1 diff --git a/tests/benchmark/run_benchmark.sh b/tests/benchmark/run_benchmark.sh index 2b9cf70fd..625d36160 100644 --- a/tests/benchmark/run_benchmark.sh +++ b/tests/benchmark/run_benchmark.sh @@ -1,6 +1,7 @@ #!/bin/bash set -xe + # 运行示例:CUDA_VISIBLE_DEVICES=0 bash run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} # 参数说明 function _set_params(){ @@ -17,6 +18,7 @@ function _set_params(){ num_gpu_devices=${#arr[*]} log_file=${run_log_path}/${model_name}_${run_mode}_bs${batch_size}_${fp_item}_${num_gpu_devices} } + function _train(){ echo "Train on ${num_gpu_devices} GPUs" echo "current CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES, gpus=$num_gpu_devices, batch_size=$batch_size" From 45a0e8c4368287da001db59dae953634ab18df24 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Thu, 16 Sep 2021 06:00:35 +0000 Subject: [PATCH 13/33] rename ckpt suffix to np --- deepspeech/training/extensions/snapshot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepspeech/training/extensions/snapshot.py b/deepspeech/training/extensions/snapshot.py index 1d3fe70cb..e81eb97fc 100644 --- a/deepspeech/training/extensions/snapshot.py +++ b/deepspeech/training/extensions/snapshot.py @@ -101,7 +101,7 @@ class Snapshot(extension.Extension): iteration = trainer.updater.state.iteration epoch = trainer.updater.state.epoch num = epoch if self.trigger[1] == 'epoch' else iteration - path = self.checkpoint_dir / f"{num}.pdz" + path = self.checkpoint_dir / f"{num}.np" # add the new one trainer.updater.save(path) From caaa44e368f1e453b969ed96f7e7bc228cf0b624 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Thu, 16 Sep 2021 06:10:27 +0000 Subject: [PATCH 14/33] varbase getitem support np.longlong since paddle 2.2.0RC --- deepspeech/utils/ctc_utils.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/deepspeech/utils/ctc_utils.py b/deepspeech/utils/ctc_utils.py index 09543d48d..6201233df 100644 --- a/deepspeech/utils/ctc_utils.py +++ b/deepspeech/utils/ctc_utils.py @@ -86,15 +86,13 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, log_alpha = paddle.zeros( (ctc_probs.size(0), len(y_insert_blank))) #(T, 2L+1) log_alpha = log_alpha - float('inf') # log of zero - # TODO(Hui Zhang): zeros not support paddle.int16 state_path = (paddle.zeros( - (ctc_probs.size(0), len(y_insert_blank)), dtype=paddle.int32) - 1 + (ctc_probs.size(0), len(y_insert_blank)), dtype=paddle.int16) - 1 ) # state path, Tuple((T, 2L+1)) # init start state - # TODO(Hui Zhang): VarBase.__getitem__() not support np.int64 - log_alpha[0, 0] = ctc_probs[0][int(y_insert_blank[0])] # State-b, Sb - log_alpha[0, 1] = ctc_probs[0][int(y_insert_blank[1])] # State-nb, Snb + log_alpha[0, 0] = ctc_probs[0][y_insert_blank[0]] # State-b, Sb + log_alpha[0, 1] = ctc_probs[0][y_insert_blank[1]] # State-nb, Snb for t in range(1, ctc_probs.size(0)): # T for s in range(len(y_insert_blank)): # 2L+1 @@ -110,13 +108,11 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, log_alpha[t - 1, s - 2], ]) prev_state = [s, s - 1, s - 2] - # TODO(Hui Zhang): VarBase.__getitem__() not support np.int64 - log_alpha[t, s] = paddle.max(candidates) + ctc_probs[t][int( - y_insert_blank[s])] + log_alpha[t, s] = paddle.max(candidates) + ctc_probs[t][ + y_insert_blank[s]] state_path[t, s] = prev_state[paddle.argmax(candidates)] - # TODO(Hui Zhang): zeros not support paddle.int16 - state_seq = -1 * paddle.ones((ctc_probs.size(0), 1), dtype=paddle.int32) + state_seq = -1 * paddle.ones((ctc_probs.size(0), 1), dtype=paddle.int16) candidates = paddle.to_tensor([ log_alpha[-1, len(y_insert_blank) - 1], # Sb From 684bb0ce90b2f2dd117de62f82c6c843d5fad619 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Thu, 16 Sep 2021 12:16:13 +0000 Subject: [PATCH 15/33] add benchmark flags, and logic --- deepspeech/exps/u2/model.py | 3 ++- deepspeech/training/cli.py | 40 ++++++++++++------------------ deepspeech/training/trainer.py | 14 +++++++++++ deepspeech/utils/utility.py | 14 ++++++++++- examples/aishell/s1/local/train.sh | 10 +++++--- examples/tiny/s1/local/train.sh | 40 +++++++++++++++++++----------- tests/benchmark/run_all.sh | 29 +++++++++++++--------- tests/benchmark/run_benchmark.sh | 21 ++++++++-------- 8 files changed, 106 insertions(+), 65 deletions(-) mode change 100644 => 100755 tests/benchmark/run_all.sh mode change 100644 => 100755 tests/benchmark/run_benchmark.sh diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 1328a1cb7..0d17d9fd2 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -100,7 +100,8 @@ class U2Trainer(Trainer): # Disable gradient synchronizations across DDP processes. # Within this context, gradients will be accumulated on module # variables, which will later be synchronized. - context = self.model.no_sync + # When using cpu w/o DDP, model does not have `no_sync` + context = self.model.no_sync if self.parallel else nullcontext else: # Used for single gpu training and DDP gradient synchronization # processes. diff --git a/deepspeech/training/cli.py b/deepspeech/training/cli.py index 1477bdfe0..d8719b3ab 100644 --- a/deepspeech/training/cli.py +++ b/deepspeech/training/cli.py @@ -44,32 +44,24 @@ def default_argument_parser(): parser = argparse.ArgumentParser() # yapf: disable - # data and output - parser.add_argument("--config", metavar="FILE", help="path of the config file to overwrite to default config with.") - parser.add_argument("--dump-config", metavar="FILE", help="dump config to yaml file.") - parser.add_argument("--output", metavar="OUTPUT_DIR", help="path to save checkpoint and logs.") - - # load from saved checkpoint - parser.add_argument("--checkpoint_path", type=str, help="path of the checkpoint to load") - - # running - parser.add_argument("--device", type=str, default='gpu', choices=["cpu", "gpu"], - help="device type to use, cpu and gpu are supported.") - parser.add_argument("--nprocs", type=int, default=1, help="number of parallel processes to use.") - - # overwrite extra config and default config - # parser.add_argument("--opts", nargs=argparse.REMAINDER, - # help="options to overwrite --config file and the default config, passing in KEY VALUE pairs") - parser.add_argument("--opts", type=str, default=[], nargs='+', - help="options to overwrite --config file and the default config, passing in KEY VALUE pairs") - - # random seed - parser.add_argument("--seed", type=int, default=None, + train_group = parser.add_argument_group(title='Train Options', description=None) + train_group.add_argument("--seed", type=int, default=None, help="seed to use for paddle, np and random. None or 0 for random, else set seed.") - - # profiler - parser.add_argument('--profiler_options', type=str, default=None, + train_group.add_argument("--device", type=str, default='gpu', choices=["cpu", "gpu"], + help="device cpu and gpu are supported.") + train_group.add_argument("--nprocs", type=int, default=1, help="number of parallel processes. 0 for cpu.") + train_group.add_argument("--config", metavar="CONFIG_FILE", help="config file.") + train_group.add_argument("--output", metavar="CKPT_DIR", help="path to save checkpoint.") + train_group.add_argument("--checkpoint_path", type=str, help="path to load checkpoint") + train_group.add_argument("--opts", type=str, default=[], nargs='+', + help="overwrite --config file, passing in LIST[KEY VALUE] pairs") + train_group.add_argument("--dump-config", metavar="FILE", help="dump config to `this` file.") + + bech_group = parser.add_argument_group(title='Benchmark Options', description=None) + bech_group.add_argument('--profiler-options', type=str, default=None, help='The option of profiler, which should be in format \"key1=value1;key2=value2;key3=value3\".') + bech_group.add_argument('--benchmark-batch-size', type=int, default=None, help='batch size for benchmark.') + bech_group.add_argument('--benchmark-max-step', type=int, default=None, help='max iteration for benchmark.') # yapd: enable return parser diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index 6587f1290..9549a4dd0 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -11,6 +11,7 @@ # 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 time from pathlib import Path @@ -24,6 +25,7 @@ from deepspeech.utils import profiler from deepspeech.utils.checkpoint import Checkpoint from deepspeech.utils.log import Log from deepspeech.utils.utility import seed_all +from deepspeech.utils.utility import UpdateConfig __all__ = ["Trainer"] @@ -101,6 +103,12 @@ class Trainer(): seed_all(args.seed) logger.info(f"Set seed {args.seed}") + if self.args.benchmark_batch_size: + with UpdateConfig(self.config): + self.config.collator.batch_size = self.args.benchmark_batch_size + logger.info( + f"Benchmark reset batch-size: {self.args.benchmark_batch_size}") + def setup(self): """Setup the experiment. """ @@ -188,6 +196,12 @@ class Trainer(): if self.args.profiler_options: profiler.add_profiler_step(self.args.profiler_options) + if self.args.benchmark_max_step and self.iteration > self.args.benchmark_max_step: + logger.info( + f"Reach benchmark-max-step: {self.args.benchmark_max_step}") + sys.exit( + f"Reach benchmark-max-step: {self.args.benchmark_max_step}") + def train(self): """The training process control by epoch.""" from_scratch = self.resume_or_scratch() diff --git a/deepspeech/utils/utility.py b/deepspeech/utils/utility.py index e18fc1f77..6f84c41be 100644 --- a/deepspeech/utils/utility.py +++ b/deepspeech/utils/utility.py @@ -16,15 +16,27 @@ import distutils.util import math import os import random +from contextlib import contextmanager from typing import List import numpy as np import paddle -__all__ = ["seed_all", 'print_arguments', 'add_arguments', "log_add"] +__all__ = [ + "UpdateConfig", "seed_all", 'print_arguments', 'add_arguments', "log_add" +] + + +@contextmanager +def UpdateConfig(config): + """Update yacs config""" + config.defrost() + yield + config.freeze() def seed_all(seed: int=210329): + """freeze random generator seed.""" np.random.seed(seed) random.seed(seed) paddle.seed(seed) diff --git a/examples/aishell/s1/local/train.sh b/examples/aishell/s1/local/train.sh index e065ad6a8..5b9c45f50 100755 --- a/examples/aishell/s1/local/train.sh +++ b/examples/aishell/s1/local/train.sh @@ -1,7 +1,8 @@ #!/bin/bash - profiler_options= +benchmark_batch_size= +benchmark_max_step= # seed may break model convergence seed=0 @@ -32,12 +33,15 @@ ckpt_name=$2 mkdir -p exp python3 -u ${BIN_DIR}/train.py \ +--seed ${seed} \ --device ${device} \ --nproc ${ngpu} \ --config ${config_path} \ --output exp/${ckpt_name} \ ---profiler_options ${profiler_options} \ ---seed ${seed} +--profiler-options "${profiler-options}" \ +--benchmark-batch-size ${benchmark_batch_size} \ +--benchmark-max-step ${benchmark_max_step} + if [ ${seed} != 0 ]; then unset FLAGS_cudnn_deterministic diff --git a/examples/tiny/s1/local/train.sh b/examples/tiny/s1/local/train.sh index 374608fd1..56ceab41c 100755 --- a/examples/tiny/s1/local/train.sh +++ b/examples/tiny/s1/local/train.sh @@ -1,37 +1,49 @@ #!/bin/bash -if [ $# != 2 ];then - echo "usage: CUDA_VISIBLE_DEVICES=0 ${0} config_path ckpt_name" - exit -1 -fi +profiler_options= +benchmark_batch_size= +benchmark_max_step= + +# seed may break model convergence +seed=0 + +source ${MAIN_ROOT}/utils/parse_options.sh || exit 1; ngpu=$(echo $CUDA_VISIBLE_DEVICES | awk -F "," '{print NF}') echo "using $ngpu gpus..." -config_path=$1 -ckpt_name=$2 - device=gpu if [ ${ngpu} == 0 ];then device=cpu fi -mkdir -p exp - -# seed may break model convergence -seed=0 -if [ ${seed} != 0 ]; then +if [ ${seed} != 0 ]; then export FLAGS_cudnn_deterministic=True + echo "using seed $seed & FLAGS_cudnn_deterministic=True ..." +fi + +if [ $# != 2 ];then + echo "usage: CUDA_VISIBLE_DEVICES=0 ${0} config_path ckpt_name" + exit -1 fi +config_path=$1 +ckpt_name=$2 + +mkdir -p exp + python3 -u ${BIN_DIR}/train.py \ +--seed ${seed} \ --device ${device} \ --nproc ${ngpu} \ --config ${config_path} \ --output exp/${ckpt_name} \ ---seed ${seed} +--profiler-options "${profiler_options}" \ +--benchmark-batch-size ${benchmark_batch_size} \ +--benchmark-max-step ${benchmark_max_step} + -if [ ${seed} != 0 ]; then +if [ ${seed} != 0 ]; then unset FLAGS_cudnn_deterministic fi diff --git a/tests/benchmark/run_all.sh b/tests/benchmark/run_all.sh old mode 100644 new mode 100755 index 7aa11d0f2..6f707cdcb --- a/tests/benchmark/run_all.sh +++ b/tests/benchmark/run_all.sh @@ -1,41 +1,46 @@ #!/bin/bash +CUR_DIR=${PWD} ROOT_DIR=../../ # 提供可稳定复现性能的脚本,默认在标准docker环境内py37执行: # collect env info bash ${ROOT_DIR}/utils/pd_env_collect.sh -cat pd_env.txt +#cat pd_env.txt -# 执行目录:需说明 -pushd ${ROOT_DIR}/examples/aishell/s1 # 1 安装该模型需要的依赖 (如需开启优化策略请注明) -pushd ${ROOT_DIR}/tools; make; popd -source ${ROOT_DIR}/tools/venv/bin/activate -pushd ${ROOT_DIR}; bash setup.sh; popd +#pushd ${ROOT_DIR}/tools; make; popd +#source ${ROOT_DIR}/tools/venv/bin/activate +#pushd ${ROOT_DIR}; bash setup.sh; popd # 2 拷贝该模型需要数据、预训练模型 + +# 执行目录:需说明 +#pushd ${ROOT_DIR}/examples/aishell/s1 +pushd ${ROOT_DIR}/examples/tiny/s1 + mkdir -p exp/log -loca/data.sh &> exp/log/data.log +. path.sh +#bash local/data.sh &> exp/log/data.log # 3 批量运行(如不方便批量,1,2需放到单个模型中) -model_mode_list=(conformer) +model_mode_list=(conformer transformer) fp_item_list=(fp32) -bs_item=(32 64 96) +bs_item_list=(32 64 96) for model_mode in ${model_mode_list[@]}; do for fp_item in ${fp_item_list[@]}; do - for bs_item in ${bs_list[@]} + for bs_item in ${bs_item_list[@]} do echo "index is speed, 1gpus, begin, ${model_name}" run_mode=sp - CUDA_VISIBLE_DEVICES=0 bash run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} # (5min) + CUDA_VISIBLE_DEVICES=0 bash ${CUR_DIR}/run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} # (5min) sleep 60 echo "index is speed, 8gpus, run_mode is multi_process, begin, ${model_name}" run_mode=mp - CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 bash run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} + CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 bash ${CUR_DIR}/run_benchmark.sh ${run_mode} ${bs_item} ${fp_item} 500 ${model_mode} sleep 60 done done diff --git a/tests/benchmark/run_benchmark.sh b/tests/benchmark/run_benchmark.sh old mode 100644 new mode 100755 index 625d36160..eb1117936 --- a/tests/benchmark/run_benchmark.sh +++ b/tests/benchmark/run_benchmark.sh @@ -23,19 +23,19 @@ function _train(){ echo "Train on ${num_gpu_devices} GPUs" echo "current CUDA_VISIBLE_DEVICES=$CUDA_VISIBLE_DEVICES, gpus=$num_gpu_devices, batch_size=$batch_size" - train_cmd="--model_name=${model_name} - --batch_size=${batch_size} - --fp=${fp_item} \ - --max_iter=${max_iter} " + train_cmd="--benchmark-batch-size ${batch_size} + --benchmark-max-step ${max_iter} + conf/${model_name}.yaml ${model_name}" + case ${run_mode} in - sp) train_cmd="python -u tools/train.py "${train_cmd}" ;; + sp) train_cmd="bash local/train.sh "${train_cmd}"" ;; mp) - train_cmd="python -m paddle.distributed.launch --log_dir=./mylog --gpus=$CUDA_VISIBLE_DEVICES tools/train.py "${train_cmd}" - log_parse_file="mylog/workerlog.0" ;; + train_cmd="bash local/train.sh "${train_cmd}"" ;; *) echo "choose run_mode(sp or mp)"; exit 1; esac -# 以下不用修改 - timeout 15m ${train_cmd} > ${log_file} 2>&1 + + # 以下不用修改 + CUDA_VISIBLE_DEVICES=${device} timeout 15m ${train_cmd} > ${log_file} 2>&1 if [ $? -ne 0 ];then echo -e "${model_name}, FAIL" export job_fail_flag=1 @@ -43,7 +43,8 @@ function _train(){ echo -e "${model_name}, SUCCESS" export job_fail_flag=0 fi - kill -9 `ps -ef|grep 'python'|awk '{print $2}'` + + trap 'for pid in $(jobs -pr); do kill -KILL $pid; done' INT QUIT TERM if [ $run_mode = "mp" -a -d mylog ]; then rm ${log_file} From 5bce41e96adac961823c5ebd64620ee2c88e96e5 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Thu, 16 Sep 2021 12:35:41 +0000 Subject: [PATCH 16/33] update config with contextlib --- deepspeech/exps/deepspeech2/bin/tune.py | 191 ------------------------ deepspeech/exps/deepspeech2/model.py | 8 +- deepspeech/exps/u2/model.py | 10 +- deepspeech/exps/u2/trainer.py | 9 +- deepspeech/exps/u2_kaldi/model.py | 9 +- deepspeech/exps/u2_st/model.py | 9 +- deepspeech/models/u2/u2.py | 9 +- deepspeech/models/u2_st.py | 9 +- 8 files changed, 35 insertions(+), 219 deletions(-) delete mode 100644 deepspeech/exps/deepspeech2/bin/tune.py diff --git a/deepspeech/exps/deepspeech2/bin/tune.py b/deepspeech/exps/deepspeech2/bin/tune.py deleted file mode 100644 index 94a9b6c47..000000000 --- a/deepspeech/exps/deepspeech2/bin/tune.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright (c) 2021 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. -"""Beam search parameters tuning for DeepSpeech2 model.""" -import functools -import sys - -import numpy as np -from paddle.io import DataLoader - -from deepspeech.exps.deepspeech2.config import get_cfg_defaults -from deepspeech.io.collator import SpeechCollator -from deepspeech.io.dataset import ManifestDataset -from deepspeech.models.ds2 import DeepSpeech2Model -from deepspeech.training.cli import default_argument_parser -from deepspeech.utils import error_rate -from deepspeech.utils.utility import add_arguments -from deepspeech.utils.utility import print_arguments - - -def tune(config, args): - """Tune parameters alpha and beta incrementally.""" - if not args.num_alphas >= 0: - raise ValueError("num_alphas must be non-negative!") - if not args.num_betas >= 0: - raise ValueError("num_betas must be non-negative!") - config.defrost() - config.data.manfiest = config.data.dev_manifest - config.data.augmentation_config = "" - config.data.keep_transcription_text = True - dev_dataset = ManifestDataset.from_config(config) - - valid_loader = DataLoader( - dev_dataset, - batch_size=config.data.batch_size, - shuffle=False, - drop_last=False, - collate_fn=SpeechCollator(keep_transcription_text=True)) - - model = DeepSpeech2Model.from_pretrained(valid_loader, config, - args.checkpoint_path) - model.eval() - - # decoders only accept string encoded in utf-8 - vocab_list = valid_loader.dataset.vocab_list - errors_func = error_rate.char_errors if config.decoding.error_rate_type == 'cer' else error_rate.word_errors - - # create grid for search - cand_alphas = np.linspace(args.alpha_from, args.alpha_to, args.num_alphas) - cand_betas = np.linspace(args.beta_from, args.beta_to, args.num_betas) - params_grid = [(alpha, beta) for alpha in cand_alphas - for beta in cand_betas] - - err_sum = [0.0 for i in range(len(params_grid))] - err_ave = [0.0 for i in range(len(params_grid))] - - num_ins, len_refs, cur_batch = 0, 0, 0 - # initialize external scorer - model.decoder.init_decode(args.alpha_from, args.beta_from, - config.decoding.lang_model_path, vocab_list, - config.decoding.decoding_method) - ## incremental tuning parameters over multiple batches - print("start tuning ...") - for infer_data in valid_loader(): - if (args.num_batches >= 0) and (cur_batch >= args.num_batches): - break - - def ordid2token(texts, texts_len): - """ ord() id to chr() chr """ - trans = [] - for text, n in zip(texts, texts_len): - n = n.numpy().item() - ids = text[:n] - trans.append(''.join([chr(i) for i in ids])) - return trans - - audio, audio_len, text, text_len = infer_data - target_transcripts = ordid2token(text, text_len) - num_ins += audio.shape[0] - - # model infer - eouts, eouts_len = model.encoder(audio, audio_len) - probs = model.decoder.softmax(eouts) - - # grid search - for index, (alpha, beta) in enumerate(params_grid): - print(f"tuneing: alpha={alpha} beta={beta}") - result_transcripts = model.decoder.decode_probs( - probs.numpy(), eouts_len, vocab_list, - config.decoding.decoding_method, - config.decoding.lang_model_path, alpha, beta, - config.decoding.beam_size, config.decoding.cutoff_prob, - config.decoding.cutoff_top_n, config.decoding.num_proc_bsearch) - - for target, result in zip(target_transcripts, result_transcripts): - errors, len_ref = errors_func(target, result) - err_sum[index] += errors - - # accumulate the length of references of every batchπ - # in the first iteration - if args.alpha_from == alpha and args.beta_from == beta: - len_refs += len_ref - - err_ave[index] = err_sum[index] / len_refs - if index % 2 == 0: - sys.stdout.write('.') - sys.stdout.flush() - print("tuneing: one grid done!") - - # output on-line tuning result at the end of current batch - err_ave_min = min(err_ave) - min_index = err_ave.index(err_ave_min) - print("\nBatch %d [%d/?], current opt (alpha, beta) = (%s, %s), " - " min [%s] = %f" % - (cur_batch, num_ins, "%.3f" % params_grid[min_index][0], - "%.3f" % params_grid[min_index][1], - config.decoding.error_rate_type, err_ave_min)) - cur_batch += 1 - - # output WER/CER at every (alpha, beta) - print("\nFinal %s:\n" % config.decoding.error_rate_type) - for index in range(len(params_grid)): - print("(alpha, beta) = (%s, %s), [%s] = %f" % - ("%.3f" % params_grid[index][0], "%.3f" % params_grid[index][1], - config.decoding.error_rate_type, err_ave[index])) - - err_ave_min = min(err_ave) - min_index = err_ave.index(err_ave_min) - print("\nFinish tuning on %d batches, final opt (alpha, beta) = (%s, %s)" % - (cur_batch, "%.3f" % params_grid[min_index][0], - "%.3f" % params_grid[min_index][1])) - - print("finish tuning") - - -def main(config, args): - tune(config, args) - - -if __name__ == "__main__": - parser = default_argument_parser() - add_arg = functools.partial(add_arguments, argparser=parser) - add_arg('num_batches', int, -1, "# of batches tuning on. " - "Default -1, on whole dev set.") - add_arg('num_alphas', int, 45, "# of alpha candidates for tuning.") - add_arg('num_betas', int, 8, "# of beta candidates for tuning.") - add_arg('alpha_from', float, 1.0, "Where alpha starts tuning from.") - add_arg('alpha_to', float, 3.2, "Where alpha ends tuning with.") - add_arg('beta_from', float, 0.1, "Where beta starts tuning from.") - add_arg('beta_to', float, 0.45, "Where beta ends tuning with.") - - add_arg('batch_size', int, 256, "# of samples per batch.") - add_arg('beam_size', int, 500, "Beam search width.") - add_arg('num_proc_bsearch', int, 8, "# of CPUs for beam search.") - add_arg('cutoff_prob', float, 1.0, "Cutoff probability for pruning.") - add_arg('cutoff_top_n', int, 40, "Cutoff number for pruning.") - - args = parser.parse_args() - print_arguments(args, globals()) - - # https://yaml.org/type/float.html - config = get_cfg_defaults() - if args.config: - config.merge_from_file(args.config) - if args.opts: - config.merge_from_list(args.opts) - - config.data.batch_size = args.batch_size - config.decoding.beam_size = args.beam_size - config.decoding.num_proc_bsearch = args.num_proc_bsearch - config.decoding.cutoff_prob = args.cutoff_prob - config.decoding.cutoff_top_n = args.cutoff_top_n - - config.freeze() - print(config) - - if args.dump_config: - with open(args.dump_config, 'w') as f: - print(config, file=f) - - main(config, args) diff --git a/deepspeech/exps/deepspeech2/model.py b/deepspeech/exps/deepspeech2/model.py index fbc357ca0..df35c52c6 100644 --- a/deepspeech/exps/deepspeech2/model.py +++ b/deepspeech/exps/deepspeech2/model.py @@ -41,6 +41,7 @@ from deepspeech.utils import layer_tools from deepspeech.utils import mp_tools from deepspeech.utils.log import Autolog from deepspeech.utils.log import Log +from deepspeech.utils.utility import UpdateConfig logger = Log(__name__).getlog() @@ -147,10 +148,9 @@ class DeepSpeech2Trainer(Trainer): def setup_model(self): config = self.config.clone() - config.defrost() - config.model.feat_size = self.train_loader.collate_fn.feature_size - config.model.dict_size = self.train_loader.collate_fn.vocab_size - config.freeze() + with UpdateConfig(config): + config.model.feat_size = self.train_loader.collate_fn.feature_size + config.model.dict_size = self.train_loader.collate_fn.vocab_size if self.args.model_type == 'offline': model = DeepSpeech2Model.from_config(config.model) diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 0d17d9fd2..89d443e03 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -43,6 +43,7 @@ from deepspeech.utils import mp_tools from deepspeech.utils import text_grid from deepspeech.utils import utility from deepspeech.utils.log import Log +from deepspeech.utils.utility import UpdateConfig logger = Log(__name__).getlog() @@ -315,10 +316,11 @@ class U2Trainer(Trainer): def setup_model(self): config = self.config model_conf = config.model - model_conf.defrost() - model_conf.input_dim = self.train_loader.collate_fn.feature_size - model_conf.output_dim = self.train_loader.collate_fn.vocab_size - model_conf.freeze() + + with UpdateConfig(model_conf): + model_conf.input_dim = self.train_loader.collate_fn.feature_size + model_conf.output_dim = self.train_loader.collate_fn.vocab_size + model = U2Model.from_config(model_conf) if self.parallel: diff --git a/deepspeech/exps/u2/trainer.py b/deepspeech/exps/u2/trainer.py index fa3e6d9d7..8e8634ac3 100644 --- a/deepspeech/exps/u2/trainer.py +++ b/deepspeech/exps/u2/trainer.py @@ -32,6 +32,7 @@ from deepspeech.training.trainer import Trainer from deepspeech.training.updaters.trainer import Trainer as NewTrainer from deepspeech.utils import layer_tools from deepspeech.utils.log import Log +from deepspeech.utils.utility import UpdateConfig logger = Log(__name__).getlog() @@ -121,10 +122,10 @@ class U2Trainer(Trainer): def setup_model(self): config = self.config model_conf = config.model - model_conf.defrost() - model_conf.input_dim = self.train_loader.collate_fn.feature_size - model_conf.output_dim = self.train_loader.collate_fn.vocab_size - model_conf.freeze() + with UpdateConfig(model_conf): + model_conf.input_dim = self.train_loader.collate_fn.feature_size + model_conf.output_dim = self.train_loader.collate_fn.vocab_size + model = U2Model.from_config(model_conf) if self.parallel: diff --git a/deepspeech/exps/u2_kaldi/model.py b/deepspeech/exps/u2_kaldi/model.py index 3d15e0259..edcc34012 100644 --- a/deepspeech/exps/u2_kaldi/model.py +++ b/deepspeech/exps/u2_kaldi/model.py @@ -41,6 +41,7 @@ from deepspeech.utils import mp_tools from deepspeech.utils import text_grid from deepspeech.utils import utility from deepspeech.utils.log import Log +from deepspeech.utils.utility import UpdateConfig logger = Log(__name__).getlog() @@ -319,10 +320,10 @@ class U2Trainer(Trainer): # model model_conf = config.model - model_conf.defrost() - model_conf.input_dim = self.train_loader.feat_dim - model_conf.output_dim = self.train_loader.vocab_size - model_conf.freeze() + with UpdateConfig(model_conf): + model_conf.input_dim = self.train_loader.feat_dim + model_conf.output_dim = self.train_loader.vocab_size + model = U2Model.from_config(model_conf) if self.parallel: model = paddle.DataParallel(model) diff --git a/deepspeech/exps/u2_st/model.py b/deepspeech/exps/u2_st/model.py index 91a81503f..0fa8ed735 100644 --- a/deepspeech/exps/u2_st/model.py +++ b/deepspeech/exps/u2_st/model.py @@ -47,6 +47,7 @@ from deepspeech.utils import mp_tools from deepspeech.utils import text_grid from deepspeech.utils import utility from deepspeech.utils.log import Log +from deepspeech.utils.utility import UpdateConfig logger = Log(__name__).getlog() @@ -345,10 +346,10 @@ class U2STTrainer(Trainer): def setup_model(self): config = self.config model_conf = config.model - model_conf.defrost() - model_conf.input_dim = self.train_loader.collate_fn.feature_size - model_conf.output_dim = self.train_loader.collate_fn.vocab_size - model_conf.freeze() + with UpdateConfig(model_conf): + model_conf.input_dim = self.train_loader.collate_fn.feature_size + model_conf.output_dim = self.train_loader.collate_fn.vocab_size + model = U2STModel.from_config(model_conf) if self.parallel: diff --git a/deepspeech/models/u2/u2.py b/deepspeech/models/u2/u2.py index fd8f15471..39ed9d5d1 100644 --- a/deepspeech/models/u2/u2.py +++ b/deepspeech/models/u2/u2.py @@ -48,6 +48,7 @@ from deepspeech.utils.tensor_utils import add_sos_eos from deepspeech.utils.tensor_utils import pad_sequence from deepspeech.utils.tensor_utils import th_accuracy from deepspeech.utils.utility import log_add +from deepspeech.utils.utility import UpdateConfig __all__ = ["U2Model", "U2InferModel"] @@ -903,10 +904,10 @@ class U2Model(U2BaseModel): Returns: DeepSpeech2Model: The model built from pretrained result. """ - config.defrost() - config.input_dim = dataloader.collate_fn.feature_size - config.output_dim = dataloader.collate_fn.vocab_size - config.freeze() + with UpdateConfig(config): + config.input_dim = dataloader.collate_fn.feature_size + config.output_dim = dataloader.collate_fn.vocab_size + model = cls.from_config(config) if checkpoint_path: diff --git a/deepspeech/models/u2_st.py b/deepspeech/models/u2_st.py index 6737a549d..87ca68b29 100644 --- a/deepspeech/models/u2_st.py +++ b/deepspeech/models/u2_st.py @@ -42,6 +42,7 @@ from deepspeech.utils import layer_tools from deepspeech.utils.log import Log from deepspeech.utils.tensor_utils import add_sos_eos from deepspeech.utils.tensor_utils import th_accuracy +from deepspeech.utils.utility import UpdateConfig __all__ = ["U2STModel", "U2STInferModel"] @@ -686,10 +687,10 @@ class U2STModel(U2STBaseModel): Returns: DeepSpeech2Model: The model built from pretrained result. """ - config.defrost() - config.input_dim = dataloader.collate_fn.feature_size - config.output_dim = dataloader.collate_fn.vocab_size - config.freeze() + with UpdateConfig(config): + config.input_dim = dataloader.collate_fn.feature_size + config.output_dim = dataloader.collate_fn.vocab_size + model = cls.from_config(config) if checkpoint_path: From 888d4be63b71076cef4b84304489881d67dd1a53 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Thu, 16 Sep 2021 12:50:04 +0000 Subject: [PATCH 17/33] fix doc link --- README.md | 20 +++++++++--------- README_cn.md | 49 --------------------------------------------- docs/src/install.md | 2 +- 3 files changed, 10 insertions(+), 61 deletions(-) delete mode 100644 README_cn.md diff --git a/README.md b/README.md index 931e6331c..71bc63638 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -[中文版](README_cn.md) - # PaddlePaddle Speech to Any toolkit ![License](https://img.shields.io/badge/license-Apache%202-red.svg) @@ -11,7 +9,7 @@ ## Features - See [feature list](doc/src/feature_list.md) for more information. + See [feature list](docs/src/feature_list.md) for more information. ## Setup @@ -20,20 +18,20 @@ All tested under: * python>=3.7 * paddlepaddle>=2.2.0rc -Please see [install](doc/src/install.md). +Please see [install](docs/src/install.md). ## Getting Started -Please see [Getting Started](doc/src/getting_started.md) and [tiny egs](examples/tiny/s0/README.md). +Please see [Getting Started](docs/src/getting_started.md) and [tiny egs](examples/tiny/s0/README.md). ## More Information -* [Data Prepration](doc/src/data_preparation.md) -* [Data Augmentation](doc/src/augmentation.md) -* [Ngram LM](doc/src/ngram_lm.md) -* [Benchmark](doc/src/benchmark.md) -* [Relased Model](doc/src/released_model.md) +* [Data Prepration](docs/src/data_preparation.md) +* [Data Augmentation](docs/src/augmentation.md) +* [Ngram LM](docs/src/ngram_lm.md) +* [Benchmark](docs/src/benchmark.md) +* [Relased Model](docs/src/released_model.md) ## Questions and Help @@ -47,4 +45,4 @@ DeepSpeech is provided under the [Apache-2.0 License](./LICENSE). ## Acknowledgement -We depends on many open source repos. See [References](doc/src/reference.md) for more information. +We depends on many open source repos. See [References](docs/src/reference.md) for more information. diff --git a/README_cn.md b/README_cn.md deleted file mode 100644 index cc993f8bf..000000000 --- a/README_cn.md +++ /dev/null @@ -1,49 +0,0 @@ -[English](README.md) - -# PaddlePaddle Speech to Any toolkit - -![License](https://img.shields.io/badge/license-Apache%202-red.svg) -![python version](https://img.shields.io/badge/python-3.7+-orange.svg) -![support os](https://img.shields.io/badge/os-linux-yellow.svg) - -*DeepSpeech*是一个采用[PaddlePaddle](https://github.com/PaddlePaddle/Paddle)平台的端到端自动语音识别引擎的开源项目, -我们的愿景是为语音识别在工业应用和学术研究上,提供易于使用、高效、小型化和可扩展的工具,包括训练,推理,以及 部署。 - -## 特性 - - 参看 [特性列表](doc/src/feature_list.md)。 - - -## 安装 - -在以下环境测试验证过: - -* Ubuntu 16.04 -* python>=3.7 -* paddlepaddle>=2.2.0rc - -参看 [安装](doc/src/install.md)。 - -## 开始 - -请查看 [开始](doc/src/getting_started.md) 和 [tiny egs](examples/tiny/s0/README.md)。 - -## 更多信息 - -* [数据处理](doc/src/data_preparation.md) -* [数据增强](doc/src/augmentation.md) -* [语言模型](doc/src/ngram_lm.md) -* [Benchmark](doc/src/benchmark.md) -* [Relased Model](doc/src/released_model.md) - -## 问题和帮助 - -欢迎您在[Github讨论](https://github.com/PaddlePaddle/DeepSpeech/discussions)提交问题,[Github问题](https://github.com/PaddlePaddle/models/issues)中反馈bug。也欢迎您为这个项目做出贡献。 - -## License - -DeepSpeech 遵循[Apache-2.0开源协议](./LICENSE)。 - -## 感谢 - -开发中参考一些优秀的仓库,详情参见 [References](doc/src/reference.md)。 diff --git a/docs/src/install.md b/docs/src/install.md index 79460737b..8cecba125 100644 --- a/docs/src/install.md +++ b/docs/src/install.md @@ -4,7 +4,7 @@ To avoid the trouble of environment setup, [running in Docker container](#runnin ## Prerequisites - Python >= 3.7 -- PaddlePaddle 2.0.0 or later (please refer to the [Installation Guide](https://www.paddlepaddle.org.cn/documentation/docs/en/beginners_guide/index_en.html)) +- PaddlePaddle latest version (please refer to the [Installation Guide](https://www.paddlepaddle.org.cn/documentation/docs/en/beginners_guide/index_en.html)) ## Setup (Important) From 3ac990295879c4c268fcf757296feabf41772d40 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 02:49:36 +0000 Subject: [PATCH 18/33] log interval 1 when benchmark --- deepspeech/exps/deepspeech2/model.py | 2 +- deepspeech/training/trainer.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/deepspeech/exps/deepspeech2/model.py b/deepspeech/exps/deepspeech2/model.py index df35c52c6..128c4c822 100644 --- a/deepspeech/exps/deepspeech2/model.py +++ b/deepspeech/exps/deepspeech2/model.py @@ -100,7 +100,7 @@ class DeepSpeech2Trainer(Trainer): iteration_time = time.time() - start - msg += "train time: {:>.3f}s, ".format(iteration_time) + msg += "batch cost: {:>.3f}s, ".format(iteration_time) msg += "batch size: {}, ".format(self.config.collator.batch_size) msg += "accum: {}, ".format(train_conf.accum_grad) msg += ', '.join('{}: {:>.6f}'.format(k, v) diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index 9549a4dd0..f5e5f12a9 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -106,6 +106,7 @@ class Trainer(): if self.args.benchmark_batch_size: with UpdateConfig(self.config): self.config.collator.batch_size = self.args.benchmark_batch_size + self.config.training.log_interval = 1 logger.info( f"Benchmark reset batch-size: {self.args.benchmark_batch_size}") From 074ec4532b8457749586c5023cae224c38cfdac5 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 02:50:55 +0000 Subject: [PATCH 19/33] rename reporter.scope to ObsScope --- deepspeech/training/extensions/evaluator.py | 4 ++-- deepspeech/training/reporter.py | 2 +- deepspeech/training/updaters/trainer.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deepspeech/training/extensions/evaluator.py b/deepspeech/training/extensions/evaluator.py index d5b359829..5137dbdde 100644 --- a/deepspeech/training/extensions/evaluator.py +++ b/deepspeech/training/extensions/evaluator.py @@ -21,7 +21,7 @@ from paddle.nn import Layer from . import extension from ..reporter import DictSummary from ..reporter import report -from ..reporter import scope +from ..reporter import ObsScope from ..timer import Timer from deepspeech.utils.log import Log logger = Log(__name__).getlog() @@ -78,7 +78,7 @@ class StandardEvaluator(extension.Extension): summary = DictSummary() for batch in self.dataloader: observation = {} - with scope(observation): + with ObsScope(observation): # main evaluation computation here. with paddle.no_grad(): self.evaluate_sync(self.evaluate_core(batch)) diff --git a/deepspeech/training/reporter.py b/deepspeech/training/reporter.py index 66a81adef..7afc33f38 100644 --- a/deepspeech/training/reporter.py +++ b/deepspeech/training/reporter.py @@ -19,7 +19,7 @@ OBSERVATIONS = None @contextlib.contextmanager -def scope(observations): +def ObsScope(observations): # make `observation` the target to report to. # it is basically a dictionary that stores temporary observations global OBSERVATIONS diff --git a/deepspeech/training/updaters/trainer.py b/deepspeech/training/updaters/trainer.py index a52fb9eb3..077694659 100644 --- a/deepspeech/training/updaters/trainer.py +++ b/deepspeech/training/updaters/trainer.py @@ -24,7 +24,7 @@ import tqdm from deepspeech.training.extensions.extension import Extension from deepspeech.training.extensions.extension import PRIORITY_READER -from deepspeech.training.reporter import scope +from deepspeech.training.reporter import ObsScope from deepspeech.training.triggers import get_trigger from deepspeech.training.triggers.limit_trigger import LimitTrigger from deepspeech.training.updaters.updater import UpdaterBase @@ -144,7 +144,7 @@ class Trainer(): # you can use `report` freely in Updater.update() # updating parameters and state - with scope(self.observation): + with ObsScope(self.observation): update() p.update() From b7a4039cdad3b6d63e40adb257e3e376389d02bd Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 06:26:08 +0000 Subject: [PATCH 20/33] fix log; add report to trainer --- deepspeech/exps/deepspeech2/model.py | 22 ++++++++------- deepspeech/exps/u2/model.py | 42 ++++++++++++++++++---------- deepspeech/training/trainer.py | 35 +++++++++++++++++------ examples/aishell/s1/local/train.sh | 6 ++-- examples/tiny/s1/local/train.sh | 4 +-- 5 files changed, 70 insertions(+), 39 deletions(-) diff --git a/deepspeech/exps/deepspeech2/model.py b/deepspeech/exps/deepspeech2/model.py index 128c4c822..8272d72ee 100644 --- a/deepspeech/exps/deepspeech2/model.py +++ b/deepspeech/exps/deepspeech2/model.py @@ -36,6 +36,7 @@ from deepspeech.models.ds2_online import DeepSpeech2InferModelOnline from deepspeech.models.ds2_online import DeepSpeech2ModelOnline from deepspeech.training.gradclip import ClipGradByGlobalNormWithLog from deepspeech.training.trainer import Trainer +from deepspeech.training.reporter import report from deepspeech.utils import error_rate from deepspeech.utils import layer_tools from deepspeech.utils import mp_tools @@ -67,7 +68,9 @@ class DeepSpeech2Trainer(Trainer): super().__init__(config, args) def train_batch(self, batch_index, batch_data, msg): - train_conf = self.config.training + batch_size = self.config.collator.batch_size + accum_grad = self.config.training.accum_grad + start = time.time() # forward @@ -78,7 +81,7 @@ class DeepSpeech2Trainer(Trainer): } # loss backward - if (batch_index + 1) % train_conf.accum_grad != 0: + if (batch_index + 1) % accum_grad != 0: # Disable gradient synchronizations across DDP processes. # Within this context, gradients will be accumulated on module # variables, which will later be synchronized. @@ -93,20 +96,19 @@ class DeepSpeech2Trainer(Trainer): layer_tools.print_grads(self.model, print_func=None) # optimizer step - if (batch_index + 1) % train_conf.accum_grad == 0: + if (batch_index + 1) % accum_grad == 0: self.optimizer.step() self.optimizer.clear_grad() self.iteration += 1 iteration_time = time.time() - start - msg += "batch cost: {:>.3f}s, ".format(iteration_time) - msg += "batch size: {}, ".format(self.config.collator.batch_size) - msg += "accum: {}, ".format(train_conf.accum_grad) - msg += ', '.join('{}: {:>.6f}'.format(k, v) - for k, v in losses_np.items()) - logger.info(msg) - + for k, v in losses_np.items(): + report(k, v) + report("batch_size", batch_size) + report("accum", accum_grad) + report("step_cost", iteration_time) + if dist.get_rank() == 0 and self.visualizer: for k, v in losses_np.items(): # `step -1` since we update `step` after optimizer.step(). diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 89d443e03..68b001ca6 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -17,6 +17,7 @@ import os import sys import time from collections import defaultdict +from collections import OrderedDict from contextlib import nullcontext from pathlib import Path from typing import Optional @@ -36,6 +37,8 @@ from deepspeech.training.optimizer import OptimizerFactory from deepspeech.training.scheduler import LRSchedulerFactory from deepspeech.training.timer import Timer from deepspeech.training.trainer import Trainer +from deepspeech.training.reporter import report +from deepspeech.training.reporter import ObsScope from deepspeech.utils import ctc_utils from deepspeech.utils import error_rate from deepspeech.utils import layer_tools @@ -121,12 +124,11 @@ class U2Trainer(Trainer): iteration_time = time.time() - start if (batch_index + 1) % train_conf.log_interval == 0: - msg += "train time: {:>.3f}s, ".format(iteration_time) - msg += "batch size: {}, ".format(self.config.collator.batch_size) - msg += "accum: {}, ".format(train_conf.accum_grad) - msg += ', '.join('{}: {:>.6f}'.format(k, v) - for k, v in losses_np.items()) - logger.info(msg) + for k, v in losses_np.items(): + report(k, v) + report("batch_size", self.config.collator.batch_size) + report("accum", train_conf.accum_grad) + report("step_cost", iteration_time) if dist.get_rank() == 0 and self.visualizer: losses_np_v = losses_np.copy() @@ -199,15 +201,25 @@ class U2Trainer(Trainer): data_start_time = time.time() for batch_index, batch in enumerate(self.train_loader): dataload_time = time.time() - data_start_time - msg = "Train: Rank: {}, ".format(dist.get_rank()) - msg += "epoch: {}, ".format(self.epoch) - msg += "step: {}, ".format(self.iteration) - msg += "batch : {}/{}, ".format(batch_index + 1, - len(self.train_loader)) - msg += "lr: {:>.8f}, ".format(self.lr_scheduler()) - msg += "data time: {:>.3f}s, ".format(dataload_time) - self.train_batch(batch_index, batch, msg) - self.after_train_batch() + msg = "Train:" + observation = OrderedDict() + with ObsScope(observation): + report("Rank", dist.get_rank()) + report("epoch", self.epoch) + report('step', self.iteration) + report('step/total', (batch_index + 1) / len(self.train_loader)) + report("lr", self.lr_scheduler()) + self.train_batch(batch_index, batch, msg) + self.after_train_batch() + report('reader_cost', dataload_time) + observation['batch_cost'] = observation['reader_cost']+observation['step_cost'] + observation['samples'] = observation['batch_size'] + observation['ips[sent./sec]'] = observation['batch_size'] / observation['batch_cost'] + for k, v in observation.items(): + msg += f" {k}: " + msg += f"{v:>.8f}" if isinstance(v, float) else f"{v}" + msg += "," + logger.info(msg) data_start_time = time.time() except Exception as e: logger.error(e) diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index f5e5f12a9..18578b429 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -14,12 +14,15 @@ import sys import time from pathlib import Path +from collections import OrderedDict import paddle from paddle import distributed as dist from tensorboardX import SummaryWriter from deepspeech.training.timer import Timer +from deepspeech.training.reporter import report +from deepspeech.training.reporter import ObsScope from deepspeech.utils import mp_tools from deepspeech.utils import profiler from deepspeech.utils.checkpoint import Checkpoint @@ -27,6 +30,7 @@ from deepspeech.utils.log import Log from deepspeech.utils.utility import seed_all from deepspeech.utils.utility import UpdateConfig + __all__ = ["Trainer"] logger = Log(__name__).getlog() @@ -98,6 +102,9 @@ class Trainer(): self.checkpoint_dir = None self.iteration = 0 self.epoch = 0 + self.rank = dist.get_rank() + + logger.info(f"Rank: {self.rank}/{dist.get_world_size()}") if args.seed: seed_all(args.seed) @@ -223,15 +230,25 @@ class Trainer(): data_start_time = time.time() for batch_index, batch in enumerate(self.train_loader): dataload_time = time.time() - data_start_time - msg = "Train: Rank: {}, ".format(dist.get_rank()) - msg += "epoch: {}, ".format(self.epoch) - msg += "step: {}, ".format(self.iteration) - msg += "batch : {}/{}, ".format(batch_index + 1, - len(self.train_loader)) - msg += "lr: {:>.8f}, ".format(self.lr_scheduler()) - msg += "data time: {:>.3f}s, ".format(dataload_time) - self.train_batch(batch_index, batch, msg) - self.after_train_batch() + msg = "Train:" + observation = OrderedDict() + with ObsScope(observation): + report("Rank", dist.get_rank()) + report("epoch", self.epoch) + report('step', self.iteration) + report('step/total', (batch_index + 1) / len(self.train_loader)) + report("lr", self.lr_scheduler()) + self.train_batch(batch_index, batch, msg) + self.after_train_batch() + report('reader_cost', dataload_time) + observation['batch_cost'] = observation['reader_cost']+observation['step_cost'] + observation['samples'] = observation['batch_size'] + observation['ips[sent./sec]'] = observation['batch_size'] / observation['batch_cost'] + for k, v in observation.items(): + msg += f" {k}: " + msg += f"{v:>.8f}" if isinstance(v, float) else f"{v}" + msg += "," + logger.info(msg) data_start_time = time.time() except Exception as e: logger.error(e) diff --git a/examples/aishell/s1/local/train.sh b/examples/aishell/s1/local/train.sh index 5b9c45f50..1a341de76 100755 --- a/examples/aishell/s1/local/train.sh +++ b/examples/aishell/s1/local/train.sh @@ -1,8 +1,8 @@ #!/bin/bash profiler_options= -benchmark_batch_size= -benchmark_max_step= +benchmark_batch_size=0 +benchmark_max_step=0 # seed may break model convergence seed=0 @@ -52,4 +52,4 @@ if [ $? -ne 0 ]; then exit 1 fi -exit 0 \ No newline at end of file +exit 0 diff --git a/examples/tiny/s1/local/train.sh b/examples/tiny/s1/local/train.sh index 56ceab41c..5097d4d03 100755 --- a/examples/tiny/s1/local/train.sh +++ b/examples/tiny/s1/local/train.sh @@ -1,8 +1,8 @@ #!/bin/bash profiler_options= -benchmark_batch_size= -benchmark_max_step= +benchmark_batch_size=0 +benchmark_max_step=0 # seed may break model convergence seed=0 From a83bf3e8e6c0d64b1a7c2d957b64b6f0b8036271 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 06:26:35 +0000 Subject: [PATCH 21/33] format --- deepspeech/exps/deepspeech2/model.py | 4 ++-- deepspeech/exps/u2/model.py | 16 ++++++++++------ deepspeech/training/extensions/evaluator.py | 2 +- deepspeech/training/trainer.py | 19 +++++++++++-------- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/deepspeech/exps/deepspeech2/model.py b/deepspeech/exps/deepspeech2/model.py index 8272d72ee..7bf029300 100644 --- a/deepspeech/exps/deepspeech2/model.py +++ b/deepspeech/exps/deepspeech2/model.py @@ -35,8 +35,8 @@ from deepspeech.models.ds2 import DeepSpeech2Model from deepspeech.models.ds2_online import DeepSpeech2InferModelOnline from deepspeech.models.ds2_online import DeepSpeech2ModelOnline from deepspeech.training.gradclip import ClipGradByGlobalNormWithLog -from deepspeech.training.trainer import Trainer from deepspeech.training.reporter import report +from deepspeech.training.trainer import Trainer from deepspeech.utils import error_rate from deepspeech.utils import layer_tools from deepspeech.utils import mp_tools @@ -108,7 +108,7 @@ class DeepSpeech2Trainer(Trainer): report("batch_size", batch_size) report("accum", accum_grad) report("step_cost", iteration_time) - + if dist.get_rank() == 0 and self.visualizer: for k, v in losses_np.items(): # `step -1` since we update `step` after optimizer.step(). diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 68b001ca6..2e512ef1e 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -34,11 +34,11 @@ from deepspeech.io.sampler import SortagradBatchSampler from deepspeech.io.sampler import SortagradDistributedBatchSampler from deepspeech.models.u2 import U2Model from deepspeech.training.optimizer import OptimizerFactory +from deepspeech.training.reporter import ObsScope +from deepspeech.training.reporter import report from deepspeech.training.scheduler import LRSchedulerFactory from deepspeech.training.timer import Timer from deepspeech.training.trainer import Trainer -from deepspeech.training.reporter import report -from deepspeech.training.reporter import ObsScope from deepspeech.utils import ctc_utils from deepspeech.utils import error_rate from deepspeech.utils import layer_tools @@ -207,17 +207,21 @@ class U2Trainer(Trainer): report("Rank", dist.get_rank()) report("epoch", self.epoch) report('step', self.iteration) - report('step/total', (batch_index + 1) / len(self.train_loader)) + report('step/total', + (batch_index + 1) / len(self.train_loader)) report("lr", self.lr_scheduler()) self.train_batch(batch_index, batch, msg) self.after_train_batch() report('reader_cost', dataload_time) - observation['batch_cost'] = observation['reader_cost']+observation['step_cost'] + observation['batch_cost'] = observation[ + 'reader_cost'] + observation['step_cost'] observation['samples'] = observation['batch_size'] - observation['ips[sent./sec]'] = observation['batch_size'] / observation['batch_cost'] + observation['ips[sent./sec]'] = observation[ + 'batch_size'] / observation['batch_cost'] for k, v in observation.items(): msg += f" {k}: " - msg += f"{v:>.8f}" if isinstance(v, float) else f"{v}" + msg += f"{v:>.8f}" if isinstance(v, + float) else f"{v}" msg += "," logger.info(msg) data_start_time = time.time() diff --git a/deepspeech/training/extensions/evaluator.py b/deepspeech/training/extensions/evaluator.py index 5137dbdde..1026a4ec3 100644 --- a/deepspeech/training/extensions/evaluator.py +++ b/deepspeech/training/extensions/evaluator.py @@ -20,8 +20,8 @@ from paddle.nn import Layer from . import extension from ..reporter import DictSummary -from ..reporter import report from ..reporter import ObsScope +from ..reporter import report from ..timer import Timer from deepspeech.utils.log import Log logger = Log(__name__).getlog() diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index 18578b429..a5efdd541 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -13,16 +13,16 @@ # limitations under the License. import sys import time -from pathlib import Path from collections import OrderedDict +from pathlib import Path import paddle from paddle import distributed as dist from tensorboardX import SummaryWriter -from deepspeech.training.timer import Timer -from deepspeech.training.reporter import report from deepspeech.training.reporter import ObsScope +from deepspeech.training.reporter import report +from deepspeech.training.timer import Timer from deepspeech.utils import mp_tools from deepspeech.utils import profiler from deepspeech.utils.checkpoint import Checkpoint @@ -30,7 +30,6 @@ from deepspeech.utils.log import Log from deepspeech.utils.utility import seed_all from deepspeech.utils.utility import UpdateConfig - __all__ = ["Trainer"] logger = Log(__name__).getlog() @@ -236,17 +235,21 @@ class Trainer(): report("Rank", dist.get_rank()) report("epoch", self.epoch) report('step', self.iteration) - report('step/total', (batch_index + 1) / len(self.train_loader)) + report('step/total', + (batch_index + 1) / len(self.train_loader)) report("lr", self.lr_scheduler()) self.train_batch(batch_index, batch, msg) self.after_train_batch() report('reader_cost', dataload_time) - observation['batch_cost'] = observation['reader_cost']+observation['step_cost'] + observation['batch_cost'] = observation[ + 'reader_cost'] + observation['step_cost'] observation['samples'] = observation['batch_size'] - observation['ips[sent./sec]'] = observation['batch_size'] / observation['batch_cost'] + observation['ips[sent./sec]'] = observation[ + 'batch_size'] / observation['batch_cost'] for k, v in observation.items(): msg += f" {k}: " - msg += f"{v:>.8f}" if isinstance(v, float) else f"{v}" + msg += f"{v:>.8f}" if isinstance(v, + float) else f"{v}" msg += "," logger.info(msg) data_start_time = time.time() From 0cb37be4bf88aa39bd09d3c8c757551f8bf18b34 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 06:31:21 +0000 Subject: [PATCH 22/33] fix benchmark cli --- deepspeech/training/cli.py | 68 ++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/deepspeech/training/cli.py b/deepspeech/training/cli.py index d8719b3ab..07c213dbc 100644 --- a/deepspeech/training/cli.py +++ b/deepspeech/training/cli.py @@ -43,25 +43,57 @@ def default_argument_parser(): """ parser = argparse.ArgumentParser() - # yapf: disable - train_group = parser.add_argument_group(title='Train Options', description=None) - train_group.add_argument("--seed", type=int, default=None, - help="seed to use for paddle, np and random. None or 0 for random, else set seed.") - train_group.add_argument("--device", type=str, default='gpu', choices=["cpu", "gpu"], + train_group = parser.add_argument_group( + title='Train Options', description=None) + train_group.add_argument( + "--seed", + type=int, + default=None, + help="seed to use for paddle, np and random. None or 0 for random, else set seed." + ) + train_group.add_argument( + "--device", + type=str, + default='gpu', + choices=["cpu", "gpu"], help="device cpu and gpu are supported.") - train_group.add_argument("--nprocs", type=int, default=1, help="number of parallel processes. 0 for cpu.") - train_group.add_argument("--config", metavar="CONFIG_FILE", help="config file.") - train_group.add_argument("--output", metavar="CKPT_DIR", help="path to save checkpoint.") - train_group.add_argument("--checkpoint_path", type=str, help="path to load checkpoint") - train_group.add_argument("--opts", type=str, default=[], nargs='+', - help="overwrite --config file, passing in LIST[KEY VALUE] pairs") - train_group.add_argument("--dump-config", metavar="FILE", help="dump config to `this` file.") + train_group.add_argument( + "--nprocs", + type=int, + default=1, + help="number of parallel processes. 0 for cpu.") + train_group.add_argument( + "--config", metavar="CONFIG_FILE", help="config file.") + train_group.add_argument( + "--output", metavar="CKPT_DIR", help="path to save checkpoint.") + train_group.add_argument( + "--checkpoint_path", type=str, help="path to load checkpoint") + train_group.add_argument( + "--opts", + type=str, + default=[], + nargs='+', + help="overwrite --config file, passing in LIST[KEY VALUE] pairs") + train_group.add_argument( + "--dump-config", metavar="FILE", help="dump config to `this` file.") - bech_group = parser.add_argument_group(title='Benchmark Options', description=None) - bech_group.add_argument('--profiler-options', type=str, default=None, - help='The option of profiler, which should be in format \"key1=value1;key2=value2;key3=value3\".') - bech_group.add_argument('--benchmark-batch-size', type=int, default=None, help='batch size for benchmark.') - bech_group.add_argument('--benchmark-max-step', type=int, default=None, help='max iteration for benchmark.') - # yapd: enable + profile_group = parser.add_argument_group( + title='Benchmark Options', description=None) + profile_group.add_argument( + '--profiler-options', + type=str, + default=None, + help='The option of profiler, which should be in format \"key1=value1;key2=value2;key3=value3\".' + ) + profile_group.add_argument( + '--benchmark-batch-size', + type=int, + default=None, + help='batch size for benchmark.') + profile_group.add_argument( + '--benchmark-max-step', + type=int, + default=None, + help='max iteration for benchmark.') return parser From a0c5abc9c877996dc7857e272640170520fdbb8f Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 06:35:56 +0000 Subject: [PATCH 23/33] fix profiler optitons config --- examples/aishell/s1/local/train.sh | 2 +- examples/tiny/s0/local/train.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/aishell/s1/local/train.sh b/examples/aishell/s1/local/train.sh index 1a341de76..5097d4d03 100755 --- a/examples/aishell/s1/local/train.sh +++ b/examples/aishell/s1/local/train.sh @@ -38,7 +38,7 @@ python3 -u ${BIN_DIR}/train.py \ --nproc ${ngpu} \ --config ${config_path} \ --output exp/${ckpt_name} \ ---profiler-options "${profiler-options}" \ +--profiler-options "${profiler_options}" \ --benchmark-batch-size ${benchmark_batch_size} \ --benchmark-max-step ${benchmark_max_step} diff --git a/examples/tiny/s0/local/train.sh b/examples/tiny/s0/local/train.sh index f96508b4f..9a76c7ade 100755 --- a/examples/tiny/s0/local/train.sh +++ b/examples/tiny/s0/local/train.sh @@ -38,7 +38,7 @@ python3 -u ${BIN_DIR}/train.py \ --config ${config_path} \ --output exp/${ckpt_name} \ --model_type ${model_type} \ ---profiler_options "${profiler_options}" \ +--profiler-options "${profiler_options}" \ --seed ${seed} if [ ${seed} != 0 ]; then From 5c3ca63bbebbd0d51930da1678273fc2676d7e21 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 07:25:49 +0000 Subject: [PATCH 24/33] add Acknowledgements --- docs/src/reference.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/reference.md b/docs/src/reference.md index 341e13611..d3676fff2 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -1,5 +1,7 @@ # Reference +We refer these repos to build `model` and `engine`: + * [delta](https://github.com/Delta-ML/delta.git) * [espnet](https://github.com/espnet/espnet.git) * [kaldi](https://github.com/kaldi-asr/kaldi.git) From 65056743c845edbcfd4ee5af47ad380d61d0fed3 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 02:36:00 -0500 Subject: [PATCH 25/33] Kaldi (#839) * can do frames, real stft * format * stft complex, powspec, magspec * add common utils * add window process func * using frames and matmul as stft * read with 2d; window process * test with dither, remove dc offset, preermphs * add doc string * more frontend utils * add logspec * fix typing * add delpoy mergify label --- deepspeech/io/dataset.py | 12 +- third_party/__init__.py | 0 third_party/paddle_audio/__init__.py | 0 third_party/paddle_audio/frontend.py | 146 ----- third_party/paddle_audio/frontend/common.py | 201 +++++++ third_party/paddle_audio/frontend/english.wav | Bin 0 -> 35824 bytes third_party/paddle_audio/frontend/kaldi.py | 266 +++++++++ .../paddle_audio/frontend/kaldi_test.py | 533 ++++++++++++++++++ 8 files changed, 1006 insertions(+), 152 deletions(-) create mode 100644 third_party/__init__.py create mode 100644 third_party/paddle_audio/__init__.py delete mode 100644 third_party/paddle_audio/frontend.py create mode 100644 third_party/paddle_audio/frontend/common.py create mode 100644 third_party/paddle_audio/frontend/english.wav create mode 100644 third_party/paddle_audio/frontend/kaldi.py create mode 100644 third_party/paddle_audio/frontend/kaldi_test.py diff --git a/deepspeech/io/dataset.py b/deepspeech/io/dataset.py index d1fe04707..e58e03b4e 100644 --- a/deepspeech/io/dataset.py +++ b/deepspeech/io/dataset.py @@ -76,19 +76,19 @@ class ManifestDataset(Dataset): Args: manifest_path (str): manifest josn file path - max_input_len ([type], optional): maximum output seq length, + max_input_len ([type], optional): maximum output seq length, in seconds for raw wav, in frame numbers for feature data. Defaults to float('inf'). - min_input_len (float, optional): minimum input seq length, + min_input_len (float, optional): minimum input seq length, in seconds for raw wav, in frame numbers for feature data. Defaults to 0.0. - max_output_len (float, optional): maximum input seq length, + max_output_len (float, optional): maximum input seq length, in modeling units. Defaults to 500.0. - min_output_len (float, optional): minimum input seq length, + min_output_len (float, optional): minimum input seq length, in modeling units. Defaults to 0.0. - max_output_input_ratio (float, optional): maximum output seq length/output seq length ratio. + max_output_input_ratio (float, optional): maximum output seq length/output seq length ratio. Defaults to 10.0. min_output_input_ratio (float, optional): minimum output seq length/output seq length ratio. Defaults to 0.05. - + """ super().__init__() diff --git a/third_party/__init__.py b/third_party/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/paddle_audio/__init__.py b/third_party/paddle_audio/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/paddle_audio/frontend.py b/third_party/paddle_audio/frontend.py deleted file mode 100644 index 1b337732e..000000000 --- a/third_party/paddle_audio/frontend.py +++ /dev/null @@ -1,146 +0,0 @@ -from typing import Tuple -import numpy as np -import paddle -from paddle import Tensor -from paddle import nn -from paddle.nn import functional as F - - -def frame(x: Tensor, - num_samples: Tensor, - win_length: int, - hop_length: int, - clip: bool = True) -> Tuple[Tensor, Tensor]: - """Extract frames from audio. - - Parameters - ---------- - x : Tensor - Shape (N, T), batched waveform. - num_samples : Tensor - Shape (N, ), number of samples of each waveform. - win_length : int - Window length. - hop_length : int - Number of samples shifted between ajancent frames. - clip : bool, optional - Whether to clip audio that does not fit into the last frame, by - default True - - Returns - ------- - frames : Tensor - Shape (N, T', win_length). - num_frames : Tensor - Shape (N, ) number of valid frames - """ - assert hop_length <= win_length - num_frames = (num_samples - win_length) // hop_length - padding = (0, 0) - if not clip: - num_frames += 1 - # NOTE: pad hop_length - 1 to the right to ensure that there is at most - # one frame dangling to the righe edge - padding = (0, hop_length - 1) - - weight = paddle.eye(win_length).unsqueeze(1) - - frames = F.conv1d(x.unsqueeze(1), - weight, - padding=padding, - stride=(hop_length, )) - return frames, num_frames - - -class STFT(nn.Layer): - """A module for computing stft transformation in a differentiable way. - - Parameters - ------------ - n_fft : int - Number of samples in a frame. - - hop_length : int - Number of samples shifted between adjacent frames. - - win_length : int - Length of the window. - - clip: bool - Whether to clip audio is necesaary. - """ - def __init__(self, - n_fft: int, - hop_length: int, - win_length: int, - window_type: str = None, - clip: bool = True): - super().__init__() - - self.hop_length = hop_length - self.n_bin = 1 + n_fft // 2 - self.n_fft = n_fft - self.clip = clip - - # calculate window - if window_type is None: - window = np.ones(win_length) - elif window_type == "hann": - window = np.hanning(win_length) - elif window_type == "hamming": - window = np.hamming(win_length) - else: - raise ValueError("Not supported yet!") - - if win_length < n_fft: - window = F.pad(window, (0, n_fft - win_length)) - elif win_length > n_fft: - window = window[:n_fft] - - # (n_bins, n_fft) complex - kernel_size = min(n_fft, win_length) - weight = np.fft.fft(np.eye(n_fft))[:self.n_bin, :kernel_size] - w_real = weight.real - w_imag = weight.imag - - # (2 * n_bins, kernel_size) - w = np.concatenate([w_real, w_imag], axis=0) - w = w * window - - # (2 * n_bins, 1, kernel_size) # (C_out, C_in, kernel_size) - w = np.expand_dims(w, 1) - weight = paddle.cast(paddle.to_tensor(w), paddle.get_default_dtype()) - self.register_buffer("weight", weight) - - def forward(self, x: Tensor, num_samples: Tensor) -> Tuple[Tensor, Tensor]: - """Compute the stft transform. - Parameters - ------------ - x : Tensor [shape=(B, T)] - The input waveform. - num_samples : Tensor - Number of samples of each waveform. - Returns - ------------ - D : Tensor - Shape(N, T', n_bins, 2) Spectrogram. - - num_frames: Tensor - Shape (N,) number of samples of each spectrogram - """ - num_frames = (num_samples - self.win_length) // self.hop_length - padding = (0, 0) - if not self.clip: - num_frames += 1 - padding = (0, self.hop_length - 1) - - batch_size, _, _ = paddle.shape(x) - x = x.unsqueeze(-1) - D = F.conv1d(self.weight, - x, - stride=(self.hop_length, ), - padding=padding, - data_format="NLC") - D = paddle.reshape(D, [batch_size, -1, self.n_bin, 2]) - return D, num_frames - diff --git a/third_party/paddle_audio/frontend/common.py b/third_party/paddle_audio/frontend/common.py new file mode 100644 index 000000000..7638dae53 --- /dev/null +++ b/third_party/paddle_audio/frontend/common.py @@ -0,0 +1,201 @@ +import paddle +import numpy as np +from typing import Tuple, Optional, Union + + +# https://github.com/kaldi-asr/kaldi/blob/cbed4ff688/src/feat/feature-window.cc#L109 +def povey_window(frame_len:int) -> np.ndarray: + win = np.empty(frame_len) + a = 2 * np.pi / (frame_len -1) + for i in range(frame_len): + win[i] = (0.5 - 0.5 * np.cos(a * i) )**0.85 + return win + +def hann_window(frame_len:int) -> np.ndarray: + win = np.empty(frame_len) + a = 2 * np.pi / (frame_len -1) + for i in range(frame_len): + win[i] = 0.5 - 0.5 * np.cos(a * i) + return win + +def sine_window(frame_len:int) -> np.ndarray: + win = np.empty(frame_len) + a = 2 * np.pi / (frame_len -1) + for i in range(frame_len): + win[i] = np.sin(0.5 * a * i) + return win + +def hamm_window(frame_len:int) -> np.ndarray: + win = np.empty(frame_len) + a = 2 * np.pi / (frame_len -1) + for i in range(frame_len): + win[i] = 0.54 - 0.46 * np.cos(a * i) + return win + +def get_window(wintype:Optional[str], winlen:int) -> np.ndarray: + """get window function + + Args: + wintype (Optional[str]): window type. + winlen (int): window length in samples. + + Raises: + ValueError: not support window. + + Returns: + np.ndarray: window coeffs. + """ + # calculate window + if not wintype or wintype == 'rectangular': + window = np.ones(winlen) + elif wintype == "hann": + window = hann_window(winlen) + elif wintype == "hamm": + window = hamm_window(winlen) + elif wintype == "povey": + window = povey_window(winlen) + else: + msg = f"{wintype} Not supported yet!" + raise ValueError(msg) + return window + + +def dft_matrix(n_fft:int, winlen:int=None, n_bin:int=None) -> Tuple[np.ndarray, np.ndarray, int]: + # https://en.wikipedia.org/wiki/Discrete_Fourier_transform + # (n_bins, n_fft) complex + if n_bin is None: + n_bin = 1 + n_fft // 2 + if winlen is None: + winlen = n_bin + # https://github.com/numpy/numpy/blob/v1.20.0/numpy/fft/_pocketfft.py#L49 + kernel_size = min(n_fft, winlen) + + n = np.arange(0, n_fft, 1.) + wsin = np.empty((n_bin, kernel_size)) #[Cout, kernel_size] + wcos = np.empty((n_bin, kernel_size)) #[Cout, kernel_size] + for k in range(n_bin): # Only half of the bins contain useful info + wsin[k,:] = -np.sin(2*np.pi*k*n/n_fft)[:kernel_size] + wcos[k,:] = np.cos(2*np.pi*k*n/n_fft)[:kernel_size] + w_real = wcos + w_imag = wsin + return w_real, w_imag, kernel_size + + +def dft_matrix_fast(n_fft:int, winlen:int=None, n_bin:int=None) -> Tuple[np.ndarray, np.ndarray, int]: + # (n_bins, n_fft) complex + if n_bin is None: + n_bin = 1 + n_fft // 2 + if winlen is None: + winlen = n_bin + # https://github.com/numpy/numpy/blob/v1.20.0/numpy/fft/_pocketfft.py#L49 + kernel_size = min(n_fft, winlen) + + # https://en.wikipedia.org/wiki/DFT_matrix + # https://ccrma.stanford.edu/~jos/st/Matrix_Formulation_DFT.html + weight = np.fft.fft(np.eye(n_fft))[:self.n_bin, :kernel_size] + w_real = weight.real + w_imag = weight.imag + return w_real, w_imag, kernel_size + + +def bin2hz(bin:Union[List[int], np.ndarray], N:int, sr:int)->List[float]: + """FFT bins to Hz. + + http://practicalcryptography.com/miscellaneous/machine-learning/intuitive-guide-discrete-fourier-transform/ + + Args: + bins (List[int] or np.ndarray): bin index. + N (int): the number of samples, or FFT points. + sr (int): sampling rate. + + Returns: + List[float]: Hz's. + """ + hz = bin * float(sr) / N + + +def hz2mel(hz): + """Convert a value in Hertz to Mels + + :param hz: a value in Hz. This can also be a numpy array, conversion proceeds element-wise. + :returns: a value in Mels. If an array was passed in, an identical sized array is returned. + """ + return 1127 * np.log(1+hz/700.0) + + +def mel2hz(mel): + """Convert a value in Mels to Hertz + + :param mel: a value in Mels. This can also be a numpy array, conversion proceeds element-wise. + :returns: a value in Hertz. If an array was passed in, an identical sized array is returned. + """ + return 700 * (np.exp(mel/1127.0)-1) + + + +def rms_to_db(rms: float): + """Root Mean Square to dB. + + Args: + rms ([float]): root mean square + + Returns: + float: dB + """ + return 20.0 * math.log10(max(1e-16, rms)) + + +def rms_to_dbfs(rms: float): + """Root Mean Square to dBFS. + https://fireattack.wordpress.com/2017/02/06/replaygain-loudness-normalization-and-applications/ + Audio is mix of sine wave, so 1 amp sine wave's Full scale is 0.7071, equal to -3.0103dB. + + dB = dBFS + 3.0103 + dBFS = db - 3.0103 + e.g. 0 dB = -3.0103 dBFS + + Args: + rms ([float]): root mean square + + Returns: + float: dBFS + """ + return rms_to_db(rms) - 3.0103 + + +def max_dbfs(sample_data: np.ndarray): + """Peak dBFS based on the maximum energy sample. + + Args: + sample_data ([np.ndarray]): float array, [-1, 1]. + + Returns: + float: dBFS + """ + # Peak dBFS based on the maximum energy sample. Will prevent overdrive if used for normalization. + return rms_to_dbfs(max(abs(np.min(sample_data)), abs(np.max(sample_data)))) + + +def mean_dbfs(sample_data): + """Peak dBFS based on the RMS energy. + + Args: + sample_data ([np.ndarray]): float array, [-1, 1]. + + Returns: + float: dBFS + """ + return rms_to_dbfs( + math.sqrt(np.mean(np.square(sample_data, dtype=np.float64)))) + + +def gain_db_to_ratio(gain_db: float): + """dB to ratio + + Args: + gain_db (float): gain in dB + + Returns: + float: scale in amp + """ + return math.pow(10.0, gain_db / 20.0) \ No newline at end of file diff --git a/third_party/paddle_audio/frontend/english.wav b/third_party/paddle_audio/frontend/english.wav new file mode 100644 index 0000000000000000000000000000000000000000..bb28291f69123209e6b7cc46b584d0a1f2c7bb16 GIT binary patch literal 35824 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[int, np.ndarray]: + """load wav file. + + Args: + wavpath (str): wav path. + sr (int, optional): expect sample rate. Defaults to None. + dtype (str, optional): wav data bits. Defaults to 'int16'. + + Returns: + Tuple[int, np.ndarray]: sr (int), wav (int16) [T, C]. + """ + wav, r_sr = sf.read(wavpath, start=start, stop=stop, dtype=dtype, always_2d=always_2d) + if sr: + assert sr == r_sr + return r_sr, wav + + +def write(wavpath:str, wav:np.ndarray, sr:int, dtype='PCM_16'): + """write wav file. + + Args: + wavpath (str): file path to save. + wav (np.ndarray): wav data. + sr (int): data samplerate. + dtype (str, optional): wav bit format. Defaults to 'PCM_16'. + """ + sf.write(wavpath, wav, sr, subtype=dtype) + + +def frames(x: Tensor, + num_samples: Tensor, + sr: int, + win_length: float, + stride_length: float, + clip: bool = False) -> Tuple[Tensor, Tensor]: + """Extract frames from audio. + + Parameters + ---------- + x : Tensor + Shape (B, T), batched waveform. + num_samples : Tensor + Shape (B, ), number of samples of each waveform. + sr: int + Sampling Rate. + win_length : float + Window length in ms. + stride_length : float + Stride length in ms. + clip : bool, optional + Whether to clip audio that does not fit into the last frame, by + default True + + Returns + ------- + frames : Tensor + Shape (B, T', win_length). + num_frames : Tensor + Shape (B, ) number of valid frames + """ + assert stride_length <= win_length + stride_length = int(stride_length * sr) + win_length = int(win_length * sr) + + num_frames = (num_samples - win_length) // stride_length + padding = (0, 0) + if not clip: + num_frames += 1 + need_samples = num_frames * stride_length + win_length + padding = (0, need_samples - num_samples - 1) + + weight = paddle.eye(win_length).unsqueeze(1) #[win_length, 1, win_length] + + frames = F.conv1d(x.unsqueeze(-1), + weight, + padding=padding, + stride=(stride_length, ), + data_format='NLC') + return frames, num_frames + + +def dither(signal:Tensor, dither_value=1.0)->Tensor: + """dither frames for log compute. + + Args: + signal (Tensor): [B, T, D] + dither_value (float, optional): [scalar]. Defaults to 1.0. + + Returns: + Tensor: [B, T, D] + """ + D = paddle.shape(signal)[-1] + signal += paddle.normal(shape=[1, 1, D]) * dither_value + return signal + + +def remove_dc_offset(signal:Tensor)->Tensor: + """remove dc. + + Args: + signal (Tensor): [B, T, D] + + Returns: + Tensor: [B, T, D] + """ + signal -= paddle.mean(signal, axis=-1, keepdim=True) + return signal + +def preemphasis(signal:Tensor, coeff=0.97)->Tensor: + """perform preemphasis on the input signal. + + Args: + signal (Tensor): [B, T, D], The signal to filter. + coeff (float, optional): [scalar].The preemphasis coefficient. 0 is no filter, Defaults to 0.97. + + Returns: + Tensor: [B, T, D] + """ + return paddle.concat([ + (1-coeff)*signal[:, :, 0:1], + signal[:, :, 1:] - coeff * signal[:, :, :-1] + ], axis=-1) + + +class STFT(nn.Layer): + """A module for computing stft transformation in a differentiable way. + + http://practicalcryptography.com/miscellaneous/machine-learning/intuitive-guide-discrete-fourier-transform/ + + Parameters + ------------ + n_fft : int + Number of samples in a frame. + + sr: int + Number of Samplilng rate. + + stride_length : float + Number of samples shifted between adjacent frames. + + win_length : float + Length of the window. + + clip: bool + Whether to clip audio is necesaary. + """ + def __init__(self, + n_fft: int, + sr: int, + win_length: float, + stride_length: float, + dither:float=0.0, + preemph_coeff:float=0.97, + remove_dc_offset:bool=True, + window_type: str = 'povey', + clip: bool = False): + super().__init__() + self.sr = sr + self.win_length = win_length + self.stride_length = stride_length + self.dither = dither + self.preemph_coeff = preemph_coeff + self.remove_dc_offset = remove_dc_offset + self.window_type = window_type + self.clip = clip + + self.n_fft = n_fft + self.n_bin = 1 + n_fft // 2 + + w_real, w_imag, kernel_size = dft_matrix( + self.n_fft, int(self.win_length * self.sr), self.n_bin + ) + + # calculate window + window = get_window(window_type, kernel_size) + + # (2 * n_bins, kernel_size) + w = np.concatenate([w_real, w_imag], axis=0) + w = w * window + # (kernel_size, 2 * n_bins) + w = np.transpose(w) + weight = paddle.cast(paddle.to_tensor(w), paddle.get_default_dtype()) + self.register_buffer("weight", weight) + + def forward(self, x: Tensor, num_samples: Tensor) -> Tuple[Tensor, Tensor]: + """Compute the stft transform. + Parameters + ------------ + x : Tensor [shape=(B, T)] + The input waveform. + num_samples : Tensor [shape=(B,)] + Number of samples of each waveform. + Returns + ------------ + C : Tensor + Shape(B, T', n_bins, 2) Spectrogram. + + num_frames: Tensor + Shape (B,) number of samples of each spectrogram + """ + batch_size = paddle.shape(num_samples) + F, nframe = frames(x, num_samples, self.sr, self.win_length, self.stride_length, clip=self.clip) + if self.dither: + F = dither(F, self.dither) + if self.remove_dc_offset: + F = remove_dc_offset(F) + if self.preemph_coeff: + F = preemphasis(F) + C = paddle.matmul(F, self.weight) # [B, T, K] [K, 2 * n_bins] + C = paddle.reshape(C, [batch_size, -1, 2, self.n_bin]) + C = C.transpose([0, 1, 3, 2]) + return C, nframe + + +def powspec(C:Tensor) -> Tensor: + """Compute the power spectrum |X_k|^2. + + Args: + C (Tensor): [B, T, C, 2] + + Returns: + Tensor: [B, T, C] + """ + real, imag = paddle.chunk(C, 2, axis=-1) + return paddle.square(real.squeeze(-1)) + paddle.square(imag.squeeze(-1)) + + +def magspec(C: Tensor, eps=1e-10) -> Tensor: + """Compute the magnitude spectrum |X_k|. + + Args: + C (Tensor): [B, T, C, 2] + eps (float): epsilon. + + Returns: + Tensor: [B, T, C] + """ + pspec = powspec(C) + return paddle.sqrt(pspec + eps) + + +def logspec(C: Tensor, eps=1e-10) -> Tensor: + """Compute log-spectrum 20log10∣X_k∣. + + Args: + C (Tensor): [description] + eps ([type], optional): [description]. Defaults to 1e-10. + + Returns: + Tensor: [description] + """ + spec = magspec(C) + return 20 * paddle.log10(spec + eps) + diff --git a/third_party/paddle_audio/frontend/kaldi_test.py b/third_party/paddle_audio/frontend/kaldi_test.py new file mode 100644 index 000000000..34ff413c5 --- /dev/null +++ b/third_party/paddle_audio/frontend/kaldi_test.py @@ -0,0 +1,533 @@ +from typing import Tuple +import numpy as np +import paddle +import unittest + +import decimal +import numpy +import math +import logging +from pathlib import Path + +from scipy.fftpack import dct + +from third_party.paddle_audio.frontend import kaldi + +def round_half_up(number): + return int(decimal.Decimal(number).quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP)) + +def rolling_window(a, window, step=1): + # http://ellisvalentiner.com/post/2017-03-21-np-strides-trick + shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) + strides = a.strides + (a.strides[-1],) + return numpy.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)[::step] + + +def do_dither(signal, dither_value=1.0): + signal += numpy.random.normal(size=signal.shape) * dither_value + return signal + +def do_remove_dc_offset(signal): + signal -= numpy.mean(signal) + return signal + +def do_preemphasis(signal, coeff=0.97): + """perform preemphasis on the input signal. + + :param signal: The signal to filter. + :param coeff: The preemphasis coefficient. 0 is no filter, default is 0.95. + :returns: the filtered signal. + """ + return numpy.append((1-coeff)*signal[0], signal[1:] - coeff * signal[:-1]) + + +def framesig(sig, frame_len, frame_step, dither=1.0, preemph=0.97, remove_dc_offset=True, wintype='hamming', stride_trick=True): + """Frame a signal into overlapping frames. + + :param sig: the audio signal to frame. + :param frame_len: length of each frame measured in samples. + :param frame_step: number of samples after the start of the previous frame that the next frame should begin. + :param winfunc: the analysis window to apply to each frame. By default no window is applied. + :param stride_trick: use stride trick to compute the rolling window and window multiplication faster + :returns: an array of frames. Size is NUMFRAMES by frame_len. + """ + slen = len(sig) + frame_len = int(round_half_up(frame_len)) + frame_step = int(round_half_up(frame_step)) + if slen <= frame_len: + numframes = 1 + else: + numframes = 1 + (( slen - frame_len) // frame_step) + + # check kaldi/src/feat/feature-window.h + padsignal = sig[:(numframes-1)*frame_step+frame_len] + if wintype is 'povey': + win = numpy.empty(frame_len) + for i in range(frame_len): + win[i] = (0.5-0.5*numpy.cos(2*numpy.pi/(frame_len-1)*i))**0.85 + else: # the hamming window + win = numpy.hamming(frame_len) + + if stride_trick: + frames = rolling_window(padsignal, window=frame_len, step=frame_step) + else: + indices = numpy.tile(numpy.arange(0, frame_len), (numframes, 1)) + numpy.tile( + numpy.arange(0, numframes * frame_step, frame_step), (frame_len, 1)).T + indices = numpy.array(indices, dtype=numpy.int32) + frames = padsignal[indices] + win = numpy.tile(win, (numframes, 1)) + + frames = frames.astype(numpy.float32) + raw_frames = numpy.zeros(frames.shape) + for frm in range(frames.shape[0]): + frames[frm,:] = do_dither(frames[frm,:], dither) # dither + frames[frm,:] = do_remove_dc_offset(frames[frm,:]) # remove dc offset + raw_frames[frm,:] = frames[frm,:] + frames[frm,:] = do_preemphasis(frames[frm,:], preemph) # preemphasize + + return frames * win, raw_frames + + +def magspec(frames, NFFT): + """Compute the magnitude spectrum of each frame in frames. If frames is an NxD matrix, output will be Nx(NFFT/2+1). + + :param frames: the array of frames. Each row is a frame. + :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are zero-padded. + :returns: If frames is an NxD matrix, output will be Nx(NFFT/2+1). Each row will be the magnitude spectrum of the corresponding frame. + """ + if numpy.shape(frames)[1] > NFFT: + logging.warn( + 'frame length (%d) is greater than FFT size (%d), frame will be truncated. Increase NFFT to avoid.', + numpy.shape(frames)[1], NFFT) + complex_spec = numpy.fft.rfft(frames, NFFT) + return numpy.absolute(complex_spec) + + +def powspec(frames, NFFT): + """Compute the power spectrum of each frame in frames. If frames is an NxD matrix, output will be Nx(NFFT/2+1). + + :param frames: the array of frames. Each row is a frame. + :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are zero-padded. + :returns: If frames is an NxD matrix, output will be Nx(NFFT/2+1). Each row will be the power spectrum of the corresponding frame. + """ + return numpy.square(magspec(frames, NFFT)) + + + +def mfcc(signal,samplerate=16000,winlen=0.025,winstep=0.01,numcep=13, + nfilt=23,nfft=512,lowfreq=20,highfreq=None,dither=1.0,remove_dc_offset=True,preemph=0.97, + ceplifter=22,useEnergy=True,wintype='povey'): + """Compute MFCC features from an audio signal. + + :param signal: the audio signal from which to compute features. Should be an N*1 array + :param samplerate: the samplerate of the signal we are working with. + :param winlen: the length of the analysis window in seconds. Default is 0.025s (25 milliseconds) + :param winstep: the step between successive windows in seconds. Default is 0.01s (10 milliseconds) + :param numcep: the number of cepstrum to return, default 13 + :param nfilt: the number of filters in the filterbank, default 26. + :param nfft: the FFT size. Default is 512. + :param lowfreq: lowest band edge of mel filters. In Hz, default is 0. + :param highfreq: highest band edge of mel filters. In Hz, default is samplerate/2 + :param preemph: apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97. + :param ceplifter: apply a lifter to final cepstral coefficients. 0 is no lifter. Default is 22. + :param appendEnergy: if this is true, the zeroth cepstral coefficient is replaced with the log of the total frame energy. + :param winfunc: the analysis window to apply to each frame. By default no window is applied. You can use numpy window functions here e.g. winfunc=numpy.hamming + :returns: A numpy array of size (NUMFRAMES by numcep) containing features. Each row holds 1 feature vector. + """ + feat,energy = fbank(signal,samplerate,winlen,winstep,nfilt,nfft,lowfreq,highfreq,dither,remove_dc_offset,preemph,wintype) + feat = numpy.log(feat) + feat = dct(feat, type=2, axis=1, norm='ortho')[:,:numcep] + feat = lifter(feat,ceplifter) + if useEnergy: feat[:,0] = numpy.log(energy) # replace first cepstral coefficient with log of frame energy + return feat + +def fbank(signal,samplerate=16000,winlen=0.025,winstep=0.01, + nfilt=40,nfft=512,lowfreq=0,highfreq=None,dither=1.0,remove_dc_offset=True, preemph=0.97, + wintype='hamming'): + """Compute Mel-filterbank energy features from an audio signal. + + :param signal: the audio signal from which to compute features. Should be an N*1 array + :param samplerate: the samplerate of the signal we are working with. + :param winlen: the length of the analysis window in seconds. Default is 0.025s (25 milliseconds) + :param winstep: the step between successive windows in seconds. Default is 0.01s (10 milliseconds) + :param nfilt: the number of filters in the filterbank, default 26. + :param nfft: the FFT size. Default is 512. + :param lowfreq: lowest band edge of mel filters. In Hz, default is 0. + :param highfreq: highest band edge of mel filters. In Hz, default is samplerate/2 + :param preemph: apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97. + :param winfunc: the analysis window to apply to each frame. By default no window is applied. You can use numpy window functions here e.g. winfunc=numpy.hamming + winfunc=lambda x:numpy.ones((x,)) + :returns: 2 values. The first is a numpy array of size (NUMFRAMES by nfilt) containing features. Each row holds 1 feature vector. The + second return value is the energy in each frame (total energy, unwindowed) + """ + highfreq= highfreq or samplerate/2 + frames,raw_frames = sigproc.framesig(signal, winlen*samplerate, winstep*samplerate, dither, preemph, remove_dc_offset, wintype) + pspec = sigproc.powspec(frames,nfft) # nearly the same until this part + energy = numpy.sum(raw_frames**2,1) # this stores the raw energy in each frame + energy = numpy.where(energy == 0,numpy.finfo(float).eps,energy) # if energy is zero, we get problems with log + + fb = get_filterbanks(nfilt,nfft,samplerate,lowfreq,highfreq) + feat = numpy.dot(pspec,fb.T) # compute the filterbank energies + feat = numpy.where(feat == 0,numpy.finfo(float).eps,feat) # if feat is zero, we get problems with log + + return feat,energy + +def logfbank(signal,samplerate=16000,winlen=0.025,winstep=0.01, + nfilt=40,nfft=512,lowfreq=64,highfreq=None,dither=1.0,remove_dc_offset=True,preemph=0.97,wintype='hamming'): + """Compute log Mel-filterbank energy features from an audio signal. + + :param signal: the audio signal from which to compute features. Should be an N*1 array + :param samplerate: the samplerate of the signal we are working with. + :param winlen: the length of the analysis window in seconds. Default is 0.025s (25 milliseconds) + :param winstep: the step between successive windows in seconds. Default is 0.01s (10 milliseconds) + :param nfilt: the number of filters in the filterbank, default 26. + :param nfft: the FFT size. Default is 512. + :param lowfreq: lowest band edge of mel filters. In Hz, default is 0. + :param highfreq: highest band edge of mel filters. In Hz, default is samplerate/2 + :param preemph: apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97. + :returns: A numpy array of size (NUMFRAMES by nfilt) containing features. Each row holds 1 feature vector. + """ + feat,energy = fbank(signal,samplerate,winlen,winstep,nfilt,nfft,lowfreq,highfreq,dither, remove_dc_offset,preemph,wintype) + return numpy.log(feat) + +def hz2mel(hz): + """Convert a value in Hertz to Mels + + :param hz: a value in Hz. This can also be a numpy array, conversion proceeds element-wise. + :returns: a value in Mels. If an array was passed in, an identical sized array is returned. + """ + return 1127 * numpy.log(1+hz/700.0) + +def mel2hz(mel): + """Convert a value in Mels to Hertz + + :param mel: a value in Mels. This can also be a numpy array, conversion proceeds element-wise. + :returns: a value in Hertz. If an array was passed in, an identical sized array is returned. + """ + return 700 * (numpy.exp(mel/1127.0)-1) + +def get_filterbanks(nfilt=26,nfft=512,samplerate=16000,lowfreq=0,highfreq=None): + """Compute a Mel-filterbank. The filters are stored in the rows, the columns correspond + to fft bins. The filters are returned as an array of size nfilt * (nfft/2 + 1) + + :param nfilt: the number of filters in the filterbank, default 20. + :param nfft: the FFT size. Default is 512. + :param samplerate: the samplerate of the signal we are working with. Affects mel spacing. + :param lowfreq: lowest band edge of mel filters, default 0 Hz + :param highfreq: highest band edge of mel filters, default samplerate/2 + :returns: A numpy array of size nfilt * (nfft/2 + 1) containing filterbank. Each row holds 1 filter. + """ + highfreq= highfreq or samplerate/2 + assert highfreq <= samplerate/2, "highfreq is greater than samplerate/2" + + # compute points evenly spaced in mels + lowmel = hz2mel(lowfreq) + highmel = hz2mel(highfreq) + + # check kaldi/src/feat/Mel-computations.h + fbank = numpy.zeros([nfilt,nfft//2+1]) + mel_freq_delta = (highmel-lowmel)/(nfilt+1) + for j in range(0,nfilt): + leftmel = lowmel+j*mel_freq_delta + centermel = lowmel+(j+1)*mel_freq_delta + rightmel = lowmel+(j+2)*mel_freq_delta + for i in range(0,nfft//2): + mel=hz2mel(i*samplerate/nfft) + if mel>leftmel and mel 0: + nframes,ncoeff = numpy.shape(cepstra) + n = numpy.arange(ncoeff) + lift = 1 + (L/2.)*numpy.sin(numpy.pi*n/L) + return lift*cepstra + else: + # values of L <= 0, do nothing + return cepstra + +def delta(feat, N): + """Compute delta features from a feature vector sequence. + + :param feat: A numpy array of size (NUMFRAMES by number of features) containing features. Each row holds 1 feature vector. + :param N: For each frame, calculate delta features based on preceding and following N frames + :returns: A numpy array of size (NUMFRAMES by number of features) containing delta features. Each row holds 1 delta feature vector. + """ + if N < 1: + raise ValueError('N must be an integer >= 1') + NUMFRAMES = len(feat) + denominator = 2 * sum([i**2 for i in range(1, N+1)]) + delta_feat = numpy.empty_like(feat) + padded = numpy.pad(feat, ((N, N), (0, 0)), mode='edge') # padded version of feat + for t in range(NUMFRAMES): + delta_feat[t] = numpy.dot(numpy.arange(-N, N+1), padded[t : t+2*N+1]) / denominator # [t : t+2*N+1] == [(N+t)-N : (N+t)+N+1] + return delta_feat + +##### modify for test ###### + +def framesig_without_dither_dc_preemphasize(sig, frame_len, frame_step, wintype='hamming', stride_trick=True): + """Frame a signal into overlapping frames. + + :param sig: the audio signal to frame. + :param frame_len: length of each frame measured in samples. + :param frame_step: number of samples after the start of the previous frame that the next frame should begin. + :param winfunc: the analysis window to apply to each frame. By default no window is applied. + :param stride_trick: use stride trick to compute the rolling window and window multiplication faster + :returns: an array of frames. Size is NUMFRAMES by frame_len. + """ + slen = len(sig) + frame_len = int(round_half_up(frame_len)) + frame_step = int(round_half_up(frame_step)) + if slen <= frame_len: + numframes = 1 + else: + numframes = 1 + (( slen - frame_len) // frame_step) + + # check kaldi/src/feat/feature-window.h + padsignal = sig[:(numframes-1)*frame_step+frame_len] + + if wintype is 'povey': + win = numpy.empty(frame_len) + for i in range(frame_len): + win[i] = (0.5-0.5*numpy.cos(2*numpy.pi/(frame_len-1)*i))**0.85 + elif wintype == '': + win = numpy.ones(frame_len) + elif wintype == 'hann': + win = numpy.hanning(frame_len) + else: # the hamming window + win = numpy.hamming(frame_len) + + if stride_trick: + frames = rolling_window(padsignal, window=frame_len, step=frame_step) + else: + indices = numpy.tile(numpy.arange(0, frame_len), (numframes, 1)) + numpy.tile( + numpy.arange(0, numframes * frame_step, frame_step), (frame_len, 1)).T + indices = numpy.array(indices, dtype=numpy.int32) + frames = padsignal[indices] + win = numpy.tile(win, (numframes, 1)) + + frames = frames.astype(numpy.float32) + raw_frames = frames + return frames * win, raw_frames + + +def frames(signal,samplerate=16000,winlen=0.025,winstep=0.01, + nfilt=40,nfft=512,lowfreq=0,highfreq=None, wintype='hamming'): + frames_with_win, raw_frames = framesig_without_dither_dc_preemphasize(signal, winlen*samplerate, winstep*samplerate, wintype) + return frames_with_win, raw_frames + + +def complexspec(frames, NFFT): + """Compute the magnitude spectrum of each frame in frames. If frames is an NxD matrix, output will be Nx(NFFT/2+1). + + :param frames: the array of frames. Each row is a frame. + :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are zero-padded. + :returns: If frames is an NxD matrix, output will be Nx(NFFT/2+1). Each row will be the magnitude spectrum of the corresponding frame. + """ + if numpy.shape(frames)[1] > NFFT: + logging.warn( + 'frame length (%d) is greater than FFT size (%d), frame will be truncated. Increase NFFT to avoid.', + numpy.shape(frames)[1], NFFT) + complex_spec = numpy.fft.rfft(frames, NFFT) + return complex_spec + + +def stft_with_window(signal,samplerate=16000,winlen=0.025,winstep=0.01, + nfilt=40,nfft=512,lowfreq=0,highfreq=None,dither=1.0,remove_dc_offset=True, preemph=0.97, + wintype='hamming'): + frames_with_win, raw_frames = framesig_without_dither_dc_preemphasize(signal, winlen*samplerate, winstep*samplerate, wintype) + + spec = magspec(frames_with_win, nfft) # nearly the same until this part + scomplex = complexspec(frames_with_win, nfft) + + rspec = magspec(raw_frames, nfft) + rcomplex = complexspec(raw_frames, nfft) + return spec, scomplex, rspec, rcomplex + + +class TestKaldiFE(unittest.TestCase): + def setUp(self): + self. this_dir = Path(__file__).parent + + self.wavpath = str(self.this_dir / 'english.wav') + self.winlen=0.025 # ms + self.winstep=0.01 # ms + self.nfft=512 + self.lowfreq = 0 + self.highfreq = None + self.wintype='hamm' + self.nfilt=40 + + paddle.set_device('cpu') + + + def test_read(self): + import scipy.io.wavfile as wav + rate, sig = wav.read(self.wavpath) + sr, wav = kaldi.read(self.wavpath) + wav = wav[:, 0] + self.assertTrue(np.all(sig == wav)) + self.assertEqual(rate, sr) + + def test_frames(self): + sr, wav = kaldi.read(self.wavpath) + wav = wav[:, 0] + _, fs = frames(wav, samplerate=sr, + winlen=self.winlen, winstep=self.winstep, + nfilt=self.nfilt, nfft=self.nfft, + lowfreq=self.lowfreq, highfreq=self.highfreq, + wintype=self.wintype) + + t_wav = paddle.to_tensor([wav], dtype='float32') + t_wavlen = paddle.to_tensor([len(wav)]) + t_fs, t_nframe = kaldi.frames(t_wav, t_wavlen, sr, self.winlen, self.winstep, clip=False) + t_fs = t_fs.astype(fs.dtype)[0] + + self.assertEqual(t_nframe.item(), fs.shape[0]) + self.assertTrue(np.allclose(t_fs.numpy(), fs)) + + + def test_stft(self): + sr, wav = kaldi.read(self.wavpath) + wav = wav[:, 0] + + for wintype in ['', 'hamm', 'hann', 'povey']: + self.wintype=wintype + _, stft_c_win, _, _ = stft_with_window(wav, samplerate=sr, + winlen=self.winlen, winstep=self.winstep, + nfilt=self.nfilt, nfft=self.nfft, + lowfreq=self.lowfreq, highfreq=self.highfreq, + wintype=self.wintype) + + t_wav = paddle.to_tensor([wav], dtype='float32') + t_wavlen = paddle.to_tensor([len(wav)]) + + stft_class = kaldi.STFT(self.nfft, sr, self.winlen, self.winstep, window_type=self.wintype, dither=0.0, preemph_coeff=0.0, remove_dc_offset=False, clip=False) + t_stft, t_nframe = stft_class(t_wav, t_wavlen) + t_stft = t_stft.astype(stft_c_win.real.dtype)[0] + t_real = t_stft[:, :, 0] + t_imag = t_stft[:, :, 1] + + self.assertEqual(t_nframe.item(), stft_c_win.real.shape[0]) + + self.assertLess(np.sum(t_real.numpy()) - np.sum(stft_c_win.real), 1) + self.assertTrue(np.allclose(t_real.numpy(), stft_c_win.real, atol=1e-1)) + + self.assertLess(np.sum(t_imag.numpy()) - np.sum(stft_c_win.imag), 1) + self.assertTrue(np.allclose(t_imag.numpy(), stft_c_win.imag, atol=1e-1)) + + + def test_magspec(self): + sr, wav = kaldi.read(self.wavpath) + wav = wav[:, 0] + for wintype in ['', 'hamm', 'hann', 'povey']: + self.wintype=wintype + stft_win, _, _, _ = stft_with_window(wav, samplerate=sr, + winlen=self.winlen, winstep=self.winstep, + nfilt=self.nfilt, nfft=self.nfft, + lowfreq=self.lowfreq, highfreq=self.highfreq, + wintype=self.wintype) + + t_wav = paddle.to_tensor([wav], dtype='float32') + t_wavlen = paddle.to_tensor([len(wav)]) + + stft_class = kaldi.STFT(self.nfft, sr, self.winlen, self.winstep, window_type=self.wintype, dither=0.0, preemph_coeff=0.0, remove_dc_offset=False, clip=False) + t_stft, t_nframe = stft_class(t_wav, t_wavlen) + t_stft = t_stft.astype(stft_win.dtype) + t_spec = kaldi.magspec(t_stft)[0] + + self.assertEqual(t_nframe.item(), stft_win.shape[0]) + + self.assertLess(np.sum(t_spec.numpy()) - np.sum(stft_win), 1) + self.assertTrue(np.allclose(t_spec.numpy(), stft_win, atol=1e-1)) + + + def test_magsepc_winprocess(self): + sr, wav = kaldi.read(self.wavpath) + wav = wav[:, 0] + fs, _= framesig(wav, self.winlen*sr, self.winstep*sr, + dither=0.0, preemph=0.97, remove_dc_offset=True, wintype='povey', stride_trick=True) + spec = magspec(fs, self.nfft) # nearly the same until this part + + t_wav = paddle.to_tensor([wav], dtype='float32') + t_wavlen = paddle.to_tensor([len(wav)]) + stft_class = kaldi.STFT( + self.nfft, sr, self.winlen, self.winstep, + window_type='povey', dither=0.0, preemph_coeff=0.97, remove_dc_offset=True, clip=False) + t_stft, t_nframe = stft_class(t_wav, t_wavlen) + t_stft = t_stft.astype(spec.dtype) + t_spec = kaldi.magspec(t_stft)[0] + + self.assertEqual(t_nframe.item(), fs.shape[0]) + + self.assertLess(np.sum(t_spec.numpy()) - np.sum(spec), 1) + self.assertTrue(np.allclose(t_spec.numpy(), spec, atol=1e-1)) + + + def test_powspec(self): + sr, wav = kaldi.read(self.wavpath) + wav = wav[:, 0] + for wintype in ['', 'hamm', 'hann', 'povey']: + self.wintype=wintype + stft_win, _, _, _ = stft_with_window(wav, samplerate=sr, + winlen=self.winlen, winstep=self.winstep, + nfilt=self.nfilt, nfft=self.nfft, + lowfreq=self.lowfreq, highfreq=self.highfreq, + wintype=self.wintype) + stft_win = np.square(stft_win) + + t_wav = paddle.to_tensor([wav], dtype='float32') + t_wavlen = paddle.to_tensor([len(wav)]) + + stft_class = kaldi.STFT(self.nfft, sr, self.winlen, self.winstep, window_type=self.wintype, dither=0.0, preemph_coeff=0.0, remove_dc_offset=False, clip=False) + t_stft, t_nframe = stft_class(t_wav, t_wavlen) + t_stft = t_stft.astype(stft_win.dtype) + t_spec = kaldi.powspec(t_stft)[0] + + self.assertEqual(t_nframe.item(), stft_win.shape[0]) + + self.assertLess(np.sum(t_spec.numpy() - stft_win), 5e4) + self.assertTrue(np.allclose(t_spec.numpy(), stft_win, atol=1e2)) + + +# from python_speech_features import mfcc +# from python_speech_features import delta +# from python_speech_features import logfbank +# import scipy.io.wavfile as wav + +# (rate,sig) = wav.read("english.wav") + +# # note that generally nfilt=40 is used for speech recognition +# fbank_feat = logfbank(sig,nfilt=23,lowfreq=20,dither=0,wintype='povey') + +# # the computed fbank coefficents of english.wav with dimension [110,23] +# # [ 12.2865 12.6906 13.1765 15.714 16.064 15.7553 16.5746 16.9205 16.6472 16.1302 16.4576 16.7326 16.8864 17.7215 18.88 19.1377 19.1495 18.6683 18.3886 20.3506 20.2772 18.8248 18.1899 +# # 11.9198 13.146 14.7215 15.8642 17.4288 16.394 16.8238 16.1095 16.4297 16.6331 16.3163 16.5093 17.4981 18.3429 19.6555 19.6263 19.8435 19.0534 19.001 20.0287 19.7707 19.5852 19.1112 +# # ... +# # ... +# # the same with that using kaldi commands: compute-fbank-feats --dither=0.0 + + +# mfcc_feat = mfcc(sig,dither=0,useEnergy=True,wintype='povey') + +# # the computed mfcc coefficents of english.wav with dimension [110,13] +# # [ 17.1337 -23.3651 -7.41751 -7.73686 -21.3682 -8.93884 -3.70843 4.68346 -16.0676 12.782 -7.24054 8.25089 10.7292 +# # 17.1692 -23.3028 -5.61872 -4.0075 -23.287 -20.6101 -5.51584 -6.15273 -14.4333 8.13052 -0.0345329 2.06274 -0.564298 +# # ... +# # ... +# # the same with that using kaldi commands: compute-mfcc-feats --dither=0.0 + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From 0877cb8a470f856b5f797460ba29b92ac3a0f0cf Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 07:43:41 +0000 Subject: [PATCH 26/33] change type_as to astype --- deepspeech/modules/encoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deepspeech/modules/encoder.py b/deepspeech/modules/encoder.py index fb44fe295..fc1ff3c83 100644 --- a/deepspeech/modules/encoder.py +++ b/deepspeech/modules/encoder.py @@ -159,7 +159,7 @@ class BaseEncoder(nn.Layer): if self.global_cmvn is not None: xs = self.global_cmvn(xs) #TODO(Hui Zhang): self.embed(xs, masks, offset=0), stride_slice not support bool tensor - xs, pos_emb, masks = self.embed(xs, masks.type_as(xs), offset=0) + xs, pos_emb, masks = self.embed(xs, masks.astype(xs.dtype), offset=0) #TODO(Hui Zhang): remove mask.astype, stride_slice not support bool tensor masks = masks.astype(paddle.bool) mask_pad = ~masks From 6cb8f94909c0ec6124d44f5ac0f42de44f2df2c6 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Fri, 17 Sep 2021 08:16:04 +0000 Subject: [PATCH 27/33] tensor.size to tensor.shape --- deepspeech/exps/u2/model.py | 2 +- deepspeech/exps/u2_kaldi/model.py | 2 +- deepspeech/exps/u2_st/model.py | 2 +- deepspeech/models/u2/u2.py | 24 ++++++++++++------------ deepspeech/models/u2_st.py | 14 +++++++------- deepspeech/modules/attention.py | 15 ++++++++------- deepspeech/modules/decoder.py | 2 +- deepspeech/modules/embedding.py | 4 ++-- deepspeech/modules/encoder.py | 20 ++++++++++---------- deepspeech/utils/ctc_utils.py | 12 ++++++------ deepspeech/utils/tensor_utils.py | 10 +++++----- 11 files changed, 54 insertions(+), 53 deletions(-) diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 2e512ef1e..7095ed749 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -579,7 +579,7 @@ class U2Tester(U2Trainer): # 1. Encoder encoder_out, encoder_mask = self.model._forward_encoder( feat, feats_length) # (B, maxlen, encoder_dim) - maxlen = encoder_out.size(1) + maxlen = encoder_out.shape[1] ctc_probs = self.model.ctc.log_softmax( encoder_out) # (1, maxlen, vocab_size) diff --git a/deepspeech/exps/u2_kaldi/model.py b/deepspeech/exps/u2_kaldi/model.py index edcc34012..c39bfe31d 100644 --- a/deepspeech/exps/u2_kaldi/model.py +++ b/deepspeech/exps/u2_kaldi/model.py @@ -557,7 +557,7 @@ class U2Tester(U2Trainer): # 1. Encoder encoder_out, encoder_mask = self.model._forward_encoder( feat, feats_length) # (B, maxlen, encoder_dim) - maxlen = encoder_out.size(1) + maxlen = encoder_out.shape[1] ctc_probs = self.model.ctc.log_softmax( encoder_out) # (1, maxlen, vocab_size) diff --git a/deepspeech/exps/u2_st/model.py b/deepspeech/exps/u2_st/model.py index 0fa8ed735..6c6e5243a 100644 --- a/deepspeech/exps/u2_st/model.py +++ b/deepspeech/exps/u2_st/model.py @@ -588,7 +588,7 @@ class U2STTester(U2STTrainer): # 1. Encoder encoder_out, encoder_mask = self.model._forward_encoder( feat, feats_length) # (B, maxlen, encoder_dim) - maxlen = encoder_out.size(1) + maxlen = encoder_out.shape[1] ctc_probs = self.model.ctc.log_softmax( encoder_out) # (1, maxlen, vocab_size) diff --git a/deepspeech/models/u2/u2.py b/deepspeech/models/u2/u2.py index 39ed9d5d1..46bbd102f 100644 --- a/deepspeech/models/u2/u2.py +++ b/deepspeech/models/u2/u2.py @@ -298,8 +298,8 @@ class U2BaseModel(nn.Layer): speech, speech_lengths, decoding_chunk_size, num_decoding_left_chunks, simulate_streaming) # (B, maxlen, encoder_dim) - maxlen = encoder_out.size(1) - encoder_dim = encoder_out.size(2) + maxlen = encoder_out.shape[1] + encoder_dim = encoder_out.shape[2] running_size = batch_size * beam_size encoder_out = encoder_out.unsqueeze(1).repeat(1, beam_size, 1, 1).view( running_size, maxlen, encoder_dim) # (B*N, maxlen, encoder_dim) @@ -404,7 +404,7 @@ class U2BaseModel(nn.Layer): encoder_out, encoder_mask = self._forward_encoder( speech, speech_lengths, decoding_chunk_size, num_decoding_left_chunks, simulate_streaming) - maxlen = encoder_out.size(1) + maxlen = encoder_out.shape[1] encoder_out_lens = encoder_mask.squeeze(1).sum(1) ctc_probs = self.ctc.log_softmax(encoder_out) # (B, maxlen, vocab_size) @@ -455,7 +455,7 @@ class U2BaseModel(nn.Layer): speech, speech_lengths, decoding_chunk_size, num_decoding_left_chunks, simulate_streaming) # (B, maxlen, encoder_dim) - maxlen = encoder_out.size(1) + maxlen = encoder_out.shape[1] ctc_probs = self.ctc.log_softmax(encoder_out) # (1, maxlen, vocab_size) ctc_probs = ctc_probs.squeeze(0) @@ -583,7 +583,7 @@ class U2BaseModel(nn.Layer): encoder_out = encoder_out.repeat(beam_size, 1, 1) encoder_mask = paddle.ones( - (beam_size, 1, encoder_out.size(1)), dtype=paddle.bool) + (beam_size, 1, encoder_out.shape[1]), dtype=paddle.bool) decoder_out, _ = self.decoder( encoder_out, encoder_mask, hyps_pad, hyps_lens) # (beam_size, max_hyps_len, vocab_size) @@ -690,13 +690,13 @@ class U2BaseModel(nn.Layer): Returns: paddle.Tensor: decoder output, (B, L) """ - assert encoder_out.size(0) == 1 - num_hyps = hyps.size(0) - assert hyps_lens.size(0) == num_hyps + assert encoder_out.shape[0] == 1 + num_hyps = hyps.shape[0] + assert hyps_lens.shape[0] == num_hyps encoder_out = encoder_out.repeat(num_hyps, 1, 1) # (B, 1, T) encoder_mask = paddle.ones( - [num_hyps, 1, encoder_out.size(1)], dtype=paddle.bool) + [num_hyps, 1, encoder_out.shape[1]], dtype=paddle.bool) # (num_hyps, max_hyps_len, vocab_size) decoder_out, _ = self.decoder(encoder_out, encoder_mask, hyps, hyps_lens) @@ -751,7 +751,7 @@ class U2BaseModel(nn.Layer): Returns: List[List[int]]: transcripts. """ - batch_size = feats.size(0) + batch_size = feats.shape[0] if decoding_method in ['ctc_prefix_beam_search', 'attention_rescoring'] and batch_size > 1: logger.fatal( @@ -779,7 +779,7 @@ class U2BaseModel(nn.Layer): # result in List[int], change it to List[List[int]] for compatible # with other batch decoding mode elif decoding_method == 'ctc_prefix_beam_search': - assert feats.size(0) == 1 + assert feats.shape[0] == 1 hyp = self.ctc_prefix_beam_search( feats, feats_lengths, @@ -789,7 +789,7 @@ class U2BaseModel(nn.Layer): simulate_streaming=simulate_streaming) hyps = [hyp] elif decoding_method == 'attention_rescoring': - assert feats.size(0) == 1 + assert feats.shape[0] == 1 hyp = self.attention_rescoring( feats, feats_lengths, diff --git a/deepspeech/models/u2_st.py b/deepspeech/models/u2_st.py index 87ca68b29..a3d99942f 100644 --- a/deepspeech/models/u2_st.py +++ b/deepspeech/models/u2_st.py @@ -340,8 +340,8 @@ class U2STBaseModel(nn.Layer): speech, speech_lengths, decoding_chunk_size, num_decoding_left_chunks, simulate_streaming) # (B, maxlen, encoder_dim) - maxlen = encoder_out.size(1) - encoder_dim = encoder_out.size(2) + maxlen = encoder_out.shape[1] + encoder_dim = encoder_out.shape[2] running_size = batch_size * beam_size encoder_out = encoder_out.unsqueeze(1).repeat(1, beam_size, 1, 1).view( running_size, maxlen, encoder_dim) # (B*N, maxlen, encoder_dim) @@ -496,13 +496,13 @@ class U2STBaseModel(nn.Layer): Returns: paddle.Tensor: decoder output, (B, L) """ - assert encoder_out.size(0) == 1 - num_hyps = hyps.size(0) - assert hyps_lens.size(0) == num_hyps + assert encoder_out.shape[0] == 1 + num_hyps = hyps.shape[0] + assert hyps_lens.shape[0] == num_hyps encoder_out = encoder_out.repeat(num_hyps, 1, 1) # (B, 1, T) encoder_mask = paddle.ones( - [num_hyps, 1, encoder_out.size(1)], dtype=paddle.bool) + [num_hyps, 1, encoder_out.shape[1]], dtype=paddle.bool) # (num_hyps, max_hyps_len, vocab_size) decoder_out, _ = self.decoder(encoder_out, encoder_mask, hyps, hyps_lens) @@ -557,7 +557,7 @@ class U2STBaseModel(nn.Layer): Returns: List[List[int]]: transcripts. """ - batch_size = feats.size(0) + batch_size = feats.shape[0] if decoding_method == 'fullsentence': hyps = self.translate( diff --git a/deepspeech/modules/attention.py b/deepspeech/modules/attention.py index 1a984dd45..f94797282 100644 --- a/deepspeech/modules/attention.py +++ b/deepspeech/modules/attention.py @@ -70,7 +70,7 @@ class MultiHeadedAttention(nn.Layer): paddle.Tensor: Transformed value tensor, size (#batch, n_head, time2, d_k). """ - n_batch = query.size(0) + n_batch = query.shape[0] q = self.linear_q(query).view(n_batch, -1, self.h, self.d_k) k = self.linear_k(key).view(n_batch, -1, self.h, self.d_k) v = self.linear_v(value).view(n_batch, -1, self.h, self.d_k) @@ -96,7 +96,7 @@ class MultiHeadedAttention(nn.Layer): paddle.Tensor: Transformed value weighted by the attention score, (#batch, time1, d_model). """ - n_batch = value.size(0) + n_batch = value.shape[0] if mask is not None: mask = mask.unsqueeze(1).eq(0) # (batch, 1, *, time2) scores = scores.masked_fill(mask, -float('inf')) @@ -172,15 +172,16 @@ class RelPositionMultiHeadedAttention(MultiHeadedAttention): paddle.Tensor: Output tensor. (batch, head, time1, time1) """ zero_pad = paddle.zeros( - (x.size(0), x.size(1), x.size(2), 1), dtype=x.dtype) + (x.shape[0], x.shape[1], x.shape[2], 1), dtype=x.dtype) x_padded = paddle.cat([zero_pad, x], dim=-1) - x_padded = x_padded.view(x.size(0), x.size(1), x.size(3) + 1, x.size(2)) + x_padded = x_padded.view(x.shape[0], x.shape[1], x.shape[3] + 1, + x.shape[2]) x = x_padded[:, :, 1:].view_as(x) # [B, H, T1, T1] if zero_triu: - ones = paddle.ones((x.size(2), x.size(3))) - x = x * paddle.tril(ones, x.size(3) - x.size(2))[None, None, :, :] + ones = paddle.ones((x.shape[2], x.shape[3])) + x = x * paddle.tril(ones, x.shape[3] - x.shape[2])[None, None, :, :] return x @@ -205,7 +206,7 @@ class RelPositionMultiHeadedAttention(MultiHeadedAttention): q, k, v = self.forward_qkv(query, key, value) q = q.transpose([0, 2, 1, 3]) # (batch, time1, head, d_k) - n_batch_pos = pos_emb.size(0) + n_batch_pos = pos_emb.shape[0] p = self.linear_pos(pos_emb).view(n_batch_pos, -1, self.h, self.d_k) p = p.transpose([0, 2, 1, 3]) # (batch, head, time1, d_k) diff --git a/deepspeech/modules/decoder.py b/deepspeech/modules/decoder.py index 143f6cc57..8ca72894a 100644 --- a/deepspeech/modules/decoder.py +++ b/deepspeech/modules/decoder.py @@ -122,7 +122,7 @@ class TransformerDecoder(nn.Layer): # tgt_mask: (B, 1, L) tgt_mask = (make_non_pad_mask(ys_in_lens).unsqueeze(1)) # m: (1, L, L) - m = subsequent_mask(tgt_mask.size(-1)).unsqueeze(0) + m = subsequent_mask(tgt_mask.shape[-1]).unsqueeze(0) # tgt_mask: (B, L, L) tgt_mask = tgt_mask & m diff --git a/deepspeech/modules/embedding.py b/deepspeech/modules/embedding.py index 98b4e1291..fbbda023c 100644 --- a/deepspeech/modules/embedding.py +++ b/deepspeech/modules/embedding.py @@ -68,7 +68,7 @@ class PositionalEncoding(nn.Layer): paddle.Tensor: for compatibility to RelPositionalEncoding, (batch=1, time, ...) """ T = x.shape[1] - assert offset + x.size(1) < self.max_len + assert offset + x.shape[1] < self.max_len #TODO(Hui Zhang): using T = x.size(1), __getitem__ not support Tensor pos_emb = self.pe[:, offset:offset + T] x = x * self.xscale + pos_emb @@ -114,7 +114,7 @@ class RelPositionalEncoding(PositionalEncoding): paddle.Tensor: Encoded tensor (batch, time, `*`). paddle.Tensor: Positional embedding tensor (1, time, `*`). """ - assert offset + x.size(1) < self.max_len + assert offset + x.shape[1] < self.max_len x = x * self.xscale #TODO(Hui Zhang): using x.size(1), __getitem__ not support Tensor pos_emb = self.pe[:, offset:offset + x.shape[1]] diff --git a/deepspeech/modules/encoder.py b/deepspeech/modules/encoder.py index fc1ff3c83..d4a8275c3 100644 --- a/deepspeech/modules/encoder.py +++ b/deepspeech/modules/encoder.py @@ -206,11 +206,11 @@ class BaseEncoder(nn.Layer): chunk computation List[paddle.Tensor]: conformer cnn cache """ - assert xs.size(0) == 1 # batch size must be one + assert xs.shape[0] == 1 # batch size must be one # tmp_masks is just for interface compatibility # TODO(Hui Zhang): stride_slice not support bool tensor # tmp_masks = paddle.ones([1, xs.size(1)], dtype=paddle.bool) - tmp_masks = paddle.ones([1, xs.size(1)], dtype=paddle.int32) + tmp_masks = paddle.ones([1, xs.shape[1]], dtype=paddle.int32) tmp_masks = tmp_masks.unsqueeze(1) #[B=1, C=1, T] if self.global_cmvn is not None: @@ -220,25 +220,25 @@ class BaseEncoder(nn.Layer): xs, tmp_masks, offset=offset) #xs=(B, T, D), pos_emb=(B=1, T, D) if subsampling_cache is not None: - cache_size = subsampling_cache.size(1) #T + cache_size = subsampling_cache.shape[1] #T xs = paddle.cat((subsampling_cache, xs), dim=1) else: cache_size = 0 # only used when using `RelPositionMultiHeadedAttention` pos_emb = self.embed.position_encoding( - offset=offset - cache_size, size=xs.size(1)) + offset=offset - cache_size, size=xs.shape[1]) if required_cache_size < 0: next_cache_start = 0 elif required_cache_size == 0: - next_cache_start = xs.size(1) + next_cache_start = xs.shape[1] else: - next_cache_start = xs.size(1) - required_cache_size + next_cache_start = xs.shape[1] - required_cache_size r_subsampling_cache = xs[:, next_cache_start:, :] # Real mask for transformer/conformer layers - masks = paddle.ones([1, xs.size(1)], dtype=paddle.bool) + masks = paddle.ones([1, xs.shape[1]], dtype=paddle.bool) masks = masks.unsqueeze(1) #[B=1, L'=1, T] r_elayers_output_cache = [] r_conformer_cnn_cache = [] @@ -302,7 +302,7 @@ class BaseEncoder(nn.Layer): stride = subsampling * decoding_chunk_size decoding_window = (decoding_chunk_size - 1) * subsampling + context - num_frames = xs.size(1) + num_frames = xs.shape[1] required_cache_size = decoding_chunk_size * num_decoding_left_chunks subsampling_cache: Optional[paddle.Tensor] = None elayers_output_cache: Optional[List[paddle.Tensor]] = None @@ -318,10 +318,10 @@ class BaseEncoder(nn.Layer): chunk_xs, offset, required_cache_size, subsampling_cache, elayers_output_cache, conformer_cnn_cache) outputs.append(y) - offset += y.size(1) + offset += y.shape[1] ys = paddle.cat(outputs, 1) # fake mask, just for jit script and compatibility with `forward` api - masks = paddle.ones([1, ys.size(1)], dtype=paddle.bool) + masks = paddle.ones([1, ys.shape[1]], dtype=paddle.bool) masks = masks.unsqueeze(1) return ys, masks diff --git a/deepspeech/utils/ctc_utils.py b/deepspeech/utils/ctc_utils.py index 09543d48d..2639f3064 100644 --- a/deepspeech/utils/ctc_utils.py +++ b/deepspeech/utils/ctc_utils.py @@ -84,11 +84,11 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, y_insert_blank = insert_blank(y, blank_id) #(2L+1) log_alpha = paddle.zeros( - (ctc_probs.size(0), len(y_insert_blank))) #(T, 2L+1) + (ctc_probs.shape[0], len(y_insert_blank))) #(T, 2L+1) log_alpha = log_alpha - float('inf') # log of zero # TODO(Hui Zhang): zeros not support paddle.int16 state_path = (paddle.zeros( - (ctc_probs.size(0), len(y_insert_blank)), dtype=paddle.int32) - 1 + (ctc_probs.shape[0], len(y_insert_blank)), dtype=paddle.int32) - 1 ) # state path, Tuple((T, 2L+1)) # init start state @@ -96,7 +96,7 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, log_alpha[0, 0] = ctc_probs[0][int(y_insert_blank[0])] # State-b, Sb log_alpha[0, 1] = ctc_probs[0][int(y_insert_blank[1])] # State-nb, Snb - for t in range(1, ctc_probs.size(0)): # T + for t in range(1, ctc_probs.shape[0]): # T for s in range(len(y_insert_blank)): # 2L+1 if y_insert_blank[s] == blank_id or s < 2 or y_insert_blank[ s] == y_insert_blank[s - 2]: @@ -116,7 +116,7 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, state_path[t, s] = prev_state[paddle.argmax(candidates)] # TODO(Hui Zhang): zeros not support paddle.int16 - state_seq = -1 * paddle.ones((ctc_probs.size(0), 1), dtype=paddle.int32) + state_seq = -1 * paddle.ones((ctc_probs.shape[0], 1), dtype=paddle.int32) candidates = paddle.to_tensor([ log_alpha[-1, len(y_insert_blank) - 1], # Sb @@ -124,11 +124,11 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, ]) prev_state = [len(y_insert_blank) - 1, len(y_insert_blank) - 2] state_seq[-1] = prev_state[paddle.argmax(candidates)] - for t in range(ctc_probs.size(0) - 2, -1, -1): + for t in range(ctc_probs.shape[0] - 2, -1, -1): state_seq[t] = state_path[t + 1, state_seq[t + 1, 0]] output_alignment = [] - for t in range(0, ctc_probs.size(0)): + for t in range(0, ctc_probs.shape[0]): output_alignment.append(y_insert_blank[state_seq[t, 0]]) return output_alignment diff --git a/deepspeech/utils/tensor_utils.py b/deepspeech/utils/tensor_utils.py index 3519f4fa5..bb7f58ded 100644 --- a/deepspeech/utils/tensor_utils.py +++ b/deepspeech/utils/tensor_utils.py @@ -83,7 +83,7 @@ def pad_sequence(sequences: List[paddle.Tensor], # (TODO Hui Zhang): slice not supprot `end==start` # trailing_dims = max_size[1:] trailing_dims = max_size[1:] if max_size.ndim >= 2 else () - max_len = max([s.size(0) for s in sequences]) + max_len = max([s.shape[0] for s in sequences]) if batch_first: out_dims = (len(sequences), max_len) + trailing_dims else: @@ -91,7 +91,7 @@ def pad_sequence(sequences: List[paddle.Tensor], out_tensor = sequences[0].new_full(out_dims, padding_value) for i, tensor in enumerate(sequences): - length = tensor.size(0) + length = tensor.shape[0] # use index notation to prevent duplicate references to the tensor if batch_first: out_tensor[i, :length, ...] = tensor @@ -139,7 +139,7 @@ def add_sos_eos(ys_pad: paddle.Tensor, sos: int, eos: int, #ys_in = [paddle.cat([_sos, y], dim=0) for y in ys] #ys_out = [paddle.cat([y, _eos], dim=0) for y in ys] #return pad_sequence(ys_in, padding_value=eos), pad_sequence(ys_out, padding_value=ignore_id) - B = ys_pad.size(0) + B = ys_pad.shape[0] _sos = paddle.ones([B, 1], dtype=ys_pad.dtype) * sos _eos = paddle.ones([B, 1], dtype=ys_pad.dtype) * eos ys_in = paddle.cat([_sos, ys_pad], dim=1) @@ -165,8 +165,8 @@ def th_accuracy(pad_outputs: paddle.Tensor, Returns: float: Accuracy value (0.0 - 1.0). """ - pad_pred = pad_outputs.view( - pad_targets.size(0), pad_targets.size(1), pad_outputs.size(1)).argmax(2) + pad_pred = pad_outputs.view(pad_targets.shape[0], pad_targets.shape[1], + pad_outputs.shape[1]).argmax(2) mask = pad_targets != ignore_label numerator = paddle.sum( pad_pred.masked_select(mask) == pad_targets.masked_select(mask)) From f422ea831e1cf5c3a4d1e2280e52e2ecb889dda9 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Sat, 18 Sep 2021 02:56:28 +0000 Subject: [PATCH 28/33] update u2 transformer config --- examples/librispeech/s1/conf/augmentation.json | 8 ++++---- examples/librispeech/s1/conf/transformer.yaml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/librispeech/s1/conf/augmentation.json b/examples/librispeech/s1/conf/augmentation.json index 8e6e97040..40a5b7900 100644 --- a/examples/librispeech/s1/conf/augmentation.json +++ b/examples/librispeech/s1/conf/augmentation.json @@ -19,17 +19,17 @@ { "type": "specaug", "params": { + "W": 0, + "warp_mode": "PIL", "F": 10, - "T": 50, "n_freq_masks": 2, + "T": 50, "n_time_masks": 2, "p": 1.0, - "W": 80, "adaptive_number_ratio": 0, "adaptive_size_ratio": 0, "max_n_time_masks": 20, - "replace_with_zero": true, - "warp_mode": "PIL" + "replace_with_zero": true }, "prob": 1.0 } diff --git a/examples/librispeech/s1/conf/transformer.yaml b/examples/librispeech/s1/conf/transformer.yaml index 4aa7b9158..fe9cab069 100644 --- a/examples/librispeech/s1/conf/transformer.yaml +++ b/examples/librispeech/s1/conf/transformer.yaml @@ -33,7 +33,7 @@ collator: keep_transcription_text: False sortagrad: True shuffle_method: batch_shuffle - num_workers: 0 + num_workers: 2 # network architecture @@ -74,7 +74,7 @@ model: training: - n_epoch: 120 + n_epoch: 120 accum_grad: 2 global_grad_clip: 5.0 optim: adam From 5a36615724ef35c9146be063a9e1e9e2d20e3e43 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Sat, 18 Sep 2021 03:07:52 +0000 Subject: [PATCH 29/33] VarBase.__getitem__ work for np.int64, np.longlong; but __setitem_varbase__ not support paddle.int16/set_value op not support --- deepspeech/exps/u2/model.py | 17 ++++++++--------- deepspeech/exps/u2_kaldi/model.py | 22 ++++++++++------------ deepspeech/exps/u2_st/model.py | 17 ++++++++--------- deepspeech/utils/ctc_utils.py | 8 +++++--- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index 1328a1cb7..a7f4f14d9 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -568,26 +568,25 @@ class U2Tester(U2Trainer): ctc_probs = ctc_probs.squeeze(0) target = target.squeeze(0) alignment = ctc_utils.forced_align(ctc_probs, target) - logger.info("align ids", key[0], alignment) + logger.info(f"align ids: {key[0]} {alignment}") fout.write('{} {}\n'.format(key[0], alignment)) # 3. gen praat # segment alignment align_segs = text_grid.segment_alignment(alignment) - logger.info("align tokens", key[0], align_segs) + logger.info(f"align tokens: {key[0]}, {align_segs}") # IntervalTier, List["start end token\n"] subsample = utility.get_subsample(self.config) tierformat = text_grid.align_to_tierformat( align_segs, subsample, token_dict) # write tier - align_output_path = os.path.join( - os.path.dirname(self.args.result_file), "align") - tier_path = os.path.join(align_output_path, key[0] + ".tier") - with open(tier_path, 'w') as f: + align_output_path = Path(self.args.result_file).parent / "align" + align_output_path.mkdir(parents=True, exist_ok=True) + tier_path = align_output_path / (key[0] + ".tier") + with tier_path.open('w') as f: f.writelines(tierformat) # write textgrid - textgrid_path = os.path.join(align_output_path, - key[0] + ".TextGrid") + textgrid_path = align_output_path / (key[0] + ".TextGrid") second_per_frame = 1. / (1000. / stride_ms) # 25ms window, 10ms stride second_per_example = ( @@ -595,7 +594,7 @@ class U2Tester(U2Trainer): text_grid.generate_textgrid( maxtime=second_per_example, intervals=tierformat, - output=textgrid_path) + output=str(textgrid_path)) def run_align(self): self.resume_or_scratch() diff --git a/deepspeech/exps/u2_kaldi/model.py b/deepspeech/exps/u2_kaldi/model.py index 3d15e0259..1dbdfef85 100644 --- a/deepspeech/exps/u2_kaldi/model.py +++ b/deepspeech/exps/u2_kaldi/model.py @@ -545,9 +545,8 @@ class U2Tester(U2Trainer): self.model.eval() logger.info(f"Align Total Examples: {len(self.align_loader.dataset)}") - stride_ms = self.config.collater.stride_ms - token_dict = self.args.char_list - + stride_ms = self.align_loader.collate_fn.stride_ms + token_dict = self.align_loader.collate_fn.vocab_list with open(self.args.result_file, 'w') as fout: # one example in batch for i, batch in enumerate(self.align_loader): @@ -564,26 +563,25 @@ class U2Tester(U2Trainer): ctc_probs = ctc_probs.squeeze(0) target = target.squeeze(0) alignment = ctc_utils.forced_align(ctc_probs, target) - logger.info("align ids", key[0], alignment) + logger.info(f"align ids: {key[0]} {alignment}") fout.write('{} {}\n'.format(key[0], alignment)) # 3. gen praat # segment alignment align_segs = text_grid.segment_alignment(alignment) - logger.info("align tokens", key[0], align_segs) + logger.info(f"align tokens: {key[0]}, {align_segs}") # IntervalTier, List["start end token\n"] subsample = utility.get_subsample(self.config) tierformat = text_grid.align_to_tierformat( align_segs, subsample, token_dict) # write tier - align_output_path = os.path.join( - os.path.dirname(self.args.result_file), "align") - tier_path = os.path.join(align_output_path, key[0] + ".tier") - with open(tier_path, 'w') as f: + align_output_path = Path(self.args.result_file).parent / "align" + align_output_path.mkdir(parents=True, exist_ok=True) + tier_path = align_output_path / (key[0] + ".tier") + with tier_path.open('w') as f: f.writelines(tierformat) # write textgrid - textgrid_path = os.path.join(align_output_path, - key[0] + ".TextGrid") + textgrid_path = align_output_path / (key[0] + ".TextGrid") second_per_frame = 1. / (1000. / stride_ms) # 25ms window, 10ms stride second_per_example = ( @@ -591,7 +589,7 @@ class U2Tester(U2Trainer): text_grid.generate_textgrid( maxtime=second_per_example, intervals=tierformat, - output=textgrid_path) + output=str(textgrid_path)) def run_align(self): self.resume_or_scratch() diff --git a/deepspeech/exps/u2_st/model.py b/deepspeech/exps/u2_st/model.py index 91a81503f..364070d23 100644 --- a/deepspeech/exps/u2_st/model.py +++ b/deepspeech/exps/u2_st/model.py @@ -595,26 +595,25 @@ class U2STTester(U2STTrainer): ctc_probs = ctc_probs.squeeze(0) target = target.squeeze(0) alignment = ctc_utils.forced_align(ctc_probs, target) - logger.info("align ids", key[0], alignment) + logger.info(f"align ids: {key[0]} {alignment}") fout.write('{} {}\n'.format(key[0], alignment)) # 3. gen praat # segment alignment align_segs = text_grid.segment_alignment(alignment) - logger.info("align tokens", key[0], align_segs) + logger.info(f"align tokens: {key[0]}, {align_segs}") # IntervalTier, List["start end token\n"] subsample = utility.get_subsample(self.config) tierformat = text_grid.align_to_tierformat( align_segs, subsample, token_dict) # write tier - align_output_path = os.path.join( - os.path.dirname(self.args.result_file), "align") - tier_path = os.path.join(align_output_path, key[0] + ".tier") - with open(tier_path, 'w') as f: + align_output_path = Path(self.args.result_file).parent / "align" + align_output_path.mkdir(parents=True, exist_ok=True) + tier_path = align_output_path / (key[0] + ".tier") + with tier_path.open('w') as f: f.writelines(tierformat) # write textgrid - textgrid_path = os.path.join(align_output_path, - key[0] + ".TextGrid") + textgrid_path = align_output_path / (key[0] + ".TextGrid") second_per_frame = 1. / (1000. / stride_ms) # 25ms window, 10ms stride second_per_example = ( @@ -622,7 +621,7 @@ class U2STTester(U2STTrainer): text_grid.generate_textgrid( maxtime=second_per_example, intervals=tierformat, - output=textgrid_path) + output=str(textgrid_path)) def run_align(self): self.resume_or_scratch() diff --git a/deepspeech/utils/ctc_utils.py b/deepspeech/utils/ctc_utils.py index 6201233df..9f2271814 100644 --- a/deepspeech/utils/ctc_utils.py +++ b/deepspeech/utils/ctc_utils.py @@ -86,8 +86,10 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, log_alpha = paddle.zeros( (ctc_probs.size(0), len(y_insert_blank))) #(T, 2L+1) log_alpha = log_alpha - float('inf') # log of zero + + # self.__setitem_varbase__(item, value) When assign a value to a paddle.Tensor, the data type of the paddle.Tensor not support int16 state_path = (paddle.zeros( - (ctc_probs.size(0), len(y_insert_blank)), dtype=paddle.int16) - 1 + (ctc_probs.size(0), len(y_insert_blank)), dtype=paddle.int32) - 1 ) # state path, Tuple((T, 2L+1)) # init start state @@ -111,8 +113,8 @@ def forced_align(ctc_probs: paddle.Tensor, y: paddle.Tensor, log_alpha[t, s] = paddle.max(candidates) + ctc_probs[t][ y_insert_blank[s]] state_path[t, s] = prev_state[paddle.argmax(candidates)] - - state_seq = -1 * paddle.ones((ctc_probs.size(0), 1), dtype=paddle.int16) + # self.__setitem_varbase__(item, value) When assign a value to a paddle.Tensor, the data type of the paddle.Tensor not support int16 + state_seq = -1 * paddle.ones((ctc_probs.size(0), 1), dtype=paddle.int32) candidates = paddle.to_tensor([ log_alpha[-1, len(y_insert_blank) - 1], # Sb From f99947e60f99ed87b435fab56cb4a191a65e8b24 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Sat, 18 Sep 2021 05:58:57 +0000 Subject: [PATCH 30/33] fix log for u2 --- deepspeech/exps/u2/model.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/deepspeech/exps/u2/model.py b/deepspeech/exps/u2/model.py index ce3d17cc2..b228c5e38 100644 --- a/deepspeech/exps/u2/model.py +++ b/deepspeech/exps/u2/model.py @@ -123,13 +123,13 @@ class U2Trainer(Trainer): iteration_time = time.time() - start - if (batch_index + 1) % train_conf.log_interval == 0: - for k, v in losses_np.items(): - report(k, v) - report("batch_size", self.config.collator.batch_size) - report("accum", train_conf.accum_grad) - report("step_cost", iteration_time) + for k, v in losses_np.items(): + report(k, v) + report("batch_size", self.config.collator.batch_size) + report("accum", train_conf.accum_grad) + report("step_cost", iteration_time) + if (batch_index + 1) % train_conf.accum_grad == 0: if dist.get_rank() == 0 and self.visualizer: losses_np_v = losses_np.copy() losses_np_v.update({"lr": self.lr_scheduler()}) @@ -223,7 +223,9 @@ class U2Trainer(Trainer): msg += f"{v:>.8f}" if isinstance(v, float) else f"{v}" msg += "," - logger.info(msg) + if (batch_index + 1 + ) % self.config.training.log_interval == 0: + logger.info(msg) data_start_time = time.time() except Exception as e: logger.error(e) From f9383a6112728af48be9f51f03b74d662861045a Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Sat, 18 Sep 2021 07:19:59 +0000 Subject: [PATCH 31/33] fix bench --- examples/tiny/s1/conf/augmentation.json | 8 ++++---- tests/benchmark/run_benchmark.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/tiny/s1/conf/augmentation.json b/examples/tiny/s1/conf/augmentation.json index 6010c2e47..9996cd4e9 100644 --- a/examples/tiny/s1/conf/augmentation.json +++ b/examples/tiny/s1/conf/augmentation.json @@ -19,17 +19,17 @@ { "type": "specaug", "params": { + "W": 0, + "warp_mode": "PIL", "F": 10, - "T": 50, "n_freq_masks": 2, + "T": 50, "n_time_masks": 2, "p": 1.0, - "W": 80, "adaptive_number_ratio": 0, "adaptive_size_ratio": 0, "max_n_time_masks": 20, - "replace_with_zero": true, - "warp_mode": "PIL" + "replace_with_zero": true }, "prob": 1.0 } diff --git a/tests/benchmark/run_benchmark.sh b/tests/benchmark/run_benchmark.sh index eb1117936..bd4655d19 100755 --- a/tests/benchmark/run_benchmark.sh +++ b/tests/benchmark/run_benchmark.sh @@ -35,7 +35,7 @@ function _train(){ esac # 以下不用修改 - CUDA_VISIBLE_DEVICES=${device} timeout 15m ${train_cmd} > ${log_file} 2>&1 + timeout 15m ${train_cmd} > ${log_file} 2>&1 if [ $? -ne 0 ];then echo -e "${model_name}, FAIL" export job_fail_flag=1 From b7510e3b65fc9c1533a00d1559b8aa22fa4453c8 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Sat, 18 Sep 2021 07:21:14 +0000 Subject: [PATCH 32/33] more prof log --- deepspeech/utils/profiler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepspeech/utils/profiler.py b/deepspeech/utils/profiler.py index 83b003cad..5733f8ed5 100644 --- a/deepspeech/utils/profiler.py +++ b/deepspeech/utils/profiler.py @@ -104,8 +104,8 @@ def add_profiler_step(options_str=None): if _profiler_options is None: _profiler_options = ProfilerOptions(options_str) - logger.info(f"{options_str}") - logger.info(f"{_profiler_options._options}") + logger.info(f"Profiler: {options_str}") + logger.info(f"Profiler: {_profiler_options._options}") if _profiler_step_id == _profiler_options['batch_range'][0]: paddle.utils.profiler.start_profiler(_profiler_options['state'], From 1a64d350c62220d2f93abb6f041892dfa4a73032 Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Sat, 18 Sep 2021 08:57:11 +0000 Subject: [PATCH 33/33] fix prof switch --- deepspeech/training/trainer.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/deepspeech/training/trainer.py b/deepspeech/training/trainer.py index a5efdd541..f4998fdf1 100644 --- a/deepspeech/training/trainer.py +++ b/deepspeech/training/trainer.py @@ -200,10 +200,8 @@ class Trainer(): batch_sampler.set_epoch(self.epoch) def after_train_batch(self): - if self.args.profiler_options: - profiler.add_profiler_step(self.args.profiler_options) - if self.args.benchmark_max_step and self.iteration > self.args.benchmark_max_step: + profiler.add_profiler_step(self.args.profiler_options) logger.info( f"Reach benchmark-max-step: {self.args.benchmark_max_step}") sys.exit(